diff --git a/agent-sdk/pom.xml b/agent-sdk/pom.xml new file mode 100644 index 0000000000000..12cd969354860 --- /dev/null +++ b/agent-sdk/pom.xml @@ -0,0 +1,36 @@ + + + + + pinpoint + com.navercorp.pinpoint + 2.3.0-SNAPSHOT + + 4.0.0 + + pinpoint-agent-sdk + pinpoint-agent-sdk + + + + + + UTF-8 + + + + + + + + + + + maven-deploy-plugin + 2.8.2 + + + + + diff --git a/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/TraceCallable.java b/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/TraceCallable.java new file mode 100644 index 0000000000000..6092743f1ef0c --- /dev/null +++ b/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/TraceCallable.java @@ -0,0 +1,46 @@ +/* + * Copyright 2021 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.sdk.v1.concurrent; + +import java.util.Objects; +import java.util.concurrent.Callable; + +/** + * {@link Callable} for TraceContext propagation + * @param return type + */ +public class TraceCallable implements Callable { + + public static Callable wrap(Callable delegate) { + return new TraceCallable<>(delegate); + } + + public static Callable wrapAndExecute(Callable delegate) { + return new TraceCallable<>(delegate); + } + + protected final Callable delegate; + + public TraceCallable(Callable delegate) { + this.delegate = Objects.requireNonNull(delegate, "delegate"); + } + + @Override + public V call() throws Exception { + return delegate.call(); + } +} diff --git a/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/TraceExecutor.java b/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/TraceExecutor.java new file mode 100644 index 0000000000000..22f2c155ef93b --- /dev/null +++ b/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/TraceExecutor.java @@ -0,0 +1,44 @@ +/* + * Copyright 2021 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.sdk.v1.concurrent; + +import com.navercorp.pinpoint.sdk.v1.concurrent.wrapper.CommandWrapper; + +import java.util.Objects; +import java.util.concurrent.Executor; + +/** + * Executor for TraceContext propagation. + */ +public class TraceExecutor implements Executor { + + protected final Executor delegate; + protected final CommandWrapper wrapper; + + public TraceExecutor(Executor delegate, CommandWrapper wrapper) { + this.delegate = Objects.requireNonNull(delegate, "delegate"); + this.wrapper = Objects.requireNonNull(wrapper, "wrapper"); + } + + + @Override + public void execute(Runnable command) { + command = wrapper.wrap(command); + delegate.execute(command); + } + +} diff --git a/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/TraceExecutorService.java b/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/TraceExecutorService.java new file mode 100644 index 0000000000000..d7b1b3698730e --- /dev/null +++ b/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/TraceExecutorService.java @@ -0,0 +1,116 @@ +/* + * Copyright 2021 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.sdk.v1.concurrent; + +import com.navercorp.pinpoint.sdk.v1.concurrent.wrapper.CommandWrapper; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +/** + * {@link ExecutorService} for TraceContext propagation. + */ +public class TraceExecutorService implements ExecutorService { + protected final ExecutorService delegate; + protected final CommandWrapper wrapper; + + public TraceExecutorService(ExecutorService delegate, CommandWrapper wrapper) { + this.delegate = Objects.requireNonNull(delegate, "delegate"); + this.wrapper = Objects.requireNonNull(wrapper, "wrapper"); + } + + @Override + public void shutdown() { + delegate.shutdown(); + } + + @Override + public List shutdownNow() { + return delegate.shutdownNow(); + } + + @Override + public boolean isShutdown() { + return delegate.isShutdown(); + } + + @Override + public boolean isTerminated() { + return delegate.isTerminated(); + } + + @Override + public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { + return delegate.awaitTermination(timeout, unit); + } + + @Override + public Future submit(Callable task) { + task = wrapper.wrap(task); + return delegate.submit(task); + } + + @Override + public Future submit(Runnable task, T result) { + task = wrapper.wrap(task); + return delegate.submit(task, result); + } + + @Override + public Future submit(Runnable task) { + task = wrapper.wrap(task); + return delegate.submit(task); + } + + @Override + public List> invokeAll(Collection> tasks) throws InterruptedException { + tasks = wrapper.wrap(tasks); + return delegate.invokeAll(tasks); + } + + @Override + public List> invokeAll(Collection> tasks, long timeout, TimeUnit unit) throws InterruptedException { + tasks = wrapper.wrap(tasks); + return delegate.invokeAll(tasks, timeout, unit); + } + + @Override + public T invokeAny(Collection> tasks) throws InterruptedException, ExecutionException { + tasks = wrapper.wrap(tasks); + return delegate.invokeAny(tasks); + } + + @Override + public T invokeAny(Collection> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + tasks = wrapper.wrap(tasks); + return delegate.invokeAny(tasks, timeout, unit); + } + + @Override + public void execute(Runnable command) { + command = wrapper.wrap(command); + delegate.execute(command); + } + +} diff --git a/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/TraceExecutors.java b/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/TraceExecutors.java new file mode 100644 index 0000000000000..38ca44effd4a7 --- /dev/null +++ b/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/TraceExecutors.java @@ -0,0 +1,73 @@ +/* + * Copyright 2021 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.sdk.v1.concurrent; + +import com.navercorp.pinpoint.sdk.v1.concurrent.wrapper.DefaultCommandWrapper; +import com.navercorp.pinpoint.sdk.v1.concurrent.wrapper.DisableCommandWrapper; +import com.navercorp.pinpoint.sdk.v1.concurrent.wrapper.CommandWrapper; + +import java.util.Objects; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ScheduledExecutorService; + +/** + * Utility class for Executor + */ +public class TraceExecutors { + + public static Executor wrapExecutor(Executor executor) { + return wrapExecutor(executor, false); + } + + public static Executor wrapExecutor(Executor executor, boolean threadContextPropagation) { + Objects.requireNonNull(executor, "executor"); + + CommandWrapper wrapper = newCommandWrapper(threadContextPropagation); + return new TraceExecutor(executor, wrapper); + } + + public static ExecutorService wrapExecutorService(ExecutorService executorService) { + return wrapExecutorService(executorService, false); + } + + public static ExecutorService wrapExecutorService(ExecutorService executorService, boolean threadContextPropagation) { + Objects.requireNonNull(executorService, "executorService"); + + CommandWrapper wrapper = newCommandWrapper(threadContextPropagation); + return new TraceExecutorService(executorService, wrapper); + } + + public static ScheduledExecutorService wrapScheduledExecutorService(ScheduledExecutorService executorService) { + return wrapScheduledExecutorService(executorService, false); + } + + public static ScheduledExecutorService wrapScheduledExecutorService(ScheduledExecutorService executorService, boolean threadContextPropagation) { + Objects.requireNonNull(executorService, "executorService"); + + CommandWrapper wrapper = newCommandWrapper(threadContextPropagation); + return new TraceScheduledExecutorService(executorService, wrapper); + } + + private static CommandWrapper newCommandWrapper(boolean threadContextPropagation) { + if (threadContextPropagation) { + return new DefaultCommandWrapper(); + } + return new DisableCommandWrapper(); + } + +} diff --git a/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/TraceForkJoinPool.java b/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/TraceForkJoinPool.java new file mode 100644 index 0000000000000..fc98b6e06401b --- /dev/null +++ b/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/TraceForkJoinPool.java @@ -0,0 +1,115 @@ +/* + * Copyright 2021 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.sdk.v1.concurrent; + +import com.navercorp.pinpoint.sdk.v1.concurrent.wrapper.DefaultCommandWrapper; +import com.navercorp.pinpoint.sdk.v1.concurrent.wrapper.CommandWrapper; + +import java.util.Collection; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +/** + * Not open yet. + */ +class TraceForkJoinPool extends ForkJoinPool { + + protected CommandWrapper commandWrapper = new DefaultCommandWrapper(); + + private TraceForkJoinPool() { + } + + private TraceForkJoinPool(int parallelism) { + super(parallelism); + } + + + private TraceForkJoinPool(int parallelism, + ForkJoinWorkerThreadFactory factory, + Thread.UncaughtExceptionHandler handler, + boolean asyncMode) { + super(parallelism, factory, handler, asyncMode); + } + + + + protected ForkJoinTask wrap(ForkJoinTask task) { + // TODO How to delegate ForkJoinTask? + return task; + } + + + + public ForkJoinTask submit(ForkJoinTask task) { + task = wrap(task); + return super.submit(task); + } + + + public ForkJoinTask submit(Callable task) { + task = commandWrapper.wrap(task); + return super.submit(task); + } + + + public ForkJoinTask submit(Runnable task, T result) { + task = commandWrapper.wrap(task); + return super.submit(task, result); + } + + + public ForkJoinTask submit(Runnable task) { + task = commandWrapper.wrap(task); + return super.submit(task); + } + + @Override + public T invokeAny(Collection> tasks) throws InterruptedException, ExecutionException { + tasks = commandWrapper.wrap(tasks); + return super.invokeAny(tasks); + } + + @Override + public T invokeAny(Collection> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + tasks = commandWrapper.wrap(tasks); + return super.invokeAny(tasks, timeout, unit); + } + + @Override + public List> invokeAll(Collection> tasks, long timeout, TimeUnit unit) throws InterruptedException { + tasks = commandWrapper.wrap(tasks); + return super.invokeAll(tasks, timeout, unit); + } + + public void execute(ForkJoinTask task) { + task = wrap(task); + super.execute(task); + } + + + public void execute(Runnable task) { + task = commandWrapper.wrap(task); + super.execute(task); + } + +} diff --git a/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/TraceRunnable.java b/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/TraceRunnable.java new file mode 100644 index 0000000000000..814421110e459 --- /dev/null +++ b/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/TraceRunnable.java @@ -0,0 +1,46 @@ +/* + * Copyright 2021 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.sdk.v1.concurrent; + +import java.util.Objects; + +/** + * {@link Runnable} for TraceContext propagation + */ +public class TraceRunnable implements Runnable { + + public static Runnable wrap(Runnable delegate) { + return new TraceRunnable(delegate); + } + + public static Runnable wrapAndExecute(Runnable delegate) { + return new TraceRunnable(delegate); + } + + protected final Runnable delegate; + + public TraceRunnable(Runnable runnable) { + this.delegate = Objects.requireNonNull(runnable, "delegate"); + } + + + + @Override + public void run() { + this.delegate.run(); + } +} diff --git a/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/TraceScheduledExecutorService.java b/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/TraceScheduledExecutorService.java new file mode 100644 index 0000000000000..9d8fdd97c7433 --- /dev/null +++ b/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/TraceScheduledExecutorService.java @@ -0,0 +1,152 @@ +/* + * Copyright 2021 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.sdk.v1.concurrent; + +import com.navercorp.pinpoint.sdk.v1.concurrent.wrapper.CommandWrapper; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +/** + * {@link ScheduledExecutorService} for TraceContext propagation. + */ +public class TraceScheduledExecutorService implements ScheduledExecutorService { + + protected final ScheduledExecutorService delegate; + protected final CommandWrapper wrapper; + + public TraceScheduledExecutorService(ScheduledExecutorService delegate, CommandWrapper wrapper) { + this.delegate = Objects.requireNonNull(delegate, "delegate"); + this.wrapper = Objects.requireNonNull(wrapper, "wrapper"); + } + + @Override + public ScheduledFuture schedule(Runnable command, long delay, TimeUnit unit) { + command = wrapper.wrap(command); + return delegate.schedule(command, delay, unit); + } + + + @Override + public ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit) { + callable = wrapper.wrap(callable); + return delegate.schedule(callable, delay, unit); + } + + @Override + public ScheduledFuture scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { + command = wrapper.wrap(command); + return delegate.scheduleAtFixedRate(command, initialDelay, period, unit); + } + + @Override + public ScheduledFuture scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) { + command = wrapper.wrap(command); + return delegate.scheduleWithFixedDelay(command, initialDelay, delay, unit); + } + + @Override + public void shutdown() { + delegate.shutdown(); + } + + @Override + public List shutdownNow() { + return delegate.shutdownNow(); + } + + @Override + public boolean isShutdown() { + return delegate.isShutdown(); + } + + @Override + public boolean isTerminated() { + return delegate.isTerminated(); + } + + @Override + public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { + return delegate.awaitTermination(timeout, unit); + } + + @Override + public Future submit(Callable task) { + task = wrapper.wrap(task); + return delegate.submit(task); + } + + @Override + public Future submit(Runnable task, T result) { + task = wrapper.wrap(task); + return delegate.submit(task, result); + } + + @Override + public Future submit(Runnable task) { + task = wrapper.wrap(task); + return delegate.submit(task); + } + + @Override + public List> invokeAll(Collection> tasks) throws InterruptedException { +// tasks = wrapper.wrap(tasks); +// return delegate.invokeAll(wrapTasks); + + return delegate.invokeAll(tasks); + } + + + + @Override + public List> invokeAll(Collection> tasks, long timeout, TimeUnit unit) throws InterruptedException { +// tasks = wrapper.wrap(tasks); +// return delegate.invokeAll(tasks, timeout, unit); + + return delegate.invokeAll(tasks, timeout, unit); + } + + @Override + public T invokeAny(Collection> tasks) throws InterruptedException, ExecutionException { +// tasks = wrapper.wrap(tasks); +// return delegate.invokeAny(wrapTasks); + + return delegate.invokeAny(tasks); + } + + @Override + public T invokeAny(Collection> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { +// tasks = wrapper.wrap(tasks); +// return delegate.invokeAny(wrapTasks, timeout, unit); + + return delegate.invokeAny(tasks, timeout, unit); + } + + @Override + public void execute(Runnable command) { + command = wrapper.wrap(command); + delegate.execute(command); + } +} diff --git a/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/wrapper/CommandWrapper.java b/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/wrapper/CommandWrapper.java new file mode 100644 index 0000000000000..29616190aeb4b --- /dev/null +++ b/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/wrapper/CommandWrapper.java @@ -0,0 +1,12 @@ +package com.navercorp.pinpoint.sdk.v1.concurrent.wrapper; + +import java.util.Collection; +import java.util.concurrent.Callable; + +public interface CommandWrapper { + Runnable wrap(Runnable command); + + Callable wrap(Callable callable); + + Collection> wrap(Collection> tasks); +} diff --git a/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/wrapper/DefaultCommandWrapper.java b/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/wrapper/DefaultCommandWrapper.java new file mode 100644 index 0000000000000..c25843d0f1f52 --- /dev/null +++ b/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/wrapper/DefaultCommandWrapper.java @@ -0,0 +1,35 @@ +package com.navercorp.pinpoint.sdk.v1.concurrent.wrapper; + +import com.navercorp.pinpoint.sdk.v1.concurrent.TraceCallable; +import com.navercorp.pinpoint.sdk.v1.concurrent.TraceRunnable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.Callable; + +public class DefaultCommandWrapper implements CommandWrapper { + + public Runnable wrap(Runnable command) { + if (command instanceof TraceRunnable) { + return command; + } + return new TraceRunnable(command); + } + + public Callable wrap(Callable callable) { + if (callable instanceof TraceCallable) { + return callable; + } + return new TraceCallable<>(callable); + } + + public Collection> wrap(Collection> tasks) { + final List> wrapList = new ArrayList<>(tasks.size()); + for (Callable task : tasks) { + Callable wrapTask = wrap(task); + wrapList.add(wrapTask); + } + return wrapList; + } +} diff --git a/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/wrapper/DisableCommandWrapper.java b/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/wrapper/DisableCommandWrapper.java new file mode 100644 index 0000000000000..b2719d236d187 --- /dev/null +++ b/agent-sdk/src/main/java/com/navercorp/pinpoint/sdk/v1/concurrent/wrapper/DisableCommandWrapper.java @@ -0,0 +1,21 @@ +package com.navercorp.pinpoint.sdk.v1.concurrent.wrapper; + +import java.util.Collection; +import java.util.concurrent.Callable; + +public class DisableCommandWrapper implements CommandWrapper { + @Override + public Runnable wrap(Runnable command) { + return command; + } + + @Override + public Callable wrap(Callable callable) { + return callable; + } + + @Override + public Collection> wrap(Collection> tasks) { + return tasks; + } +} diff --git a/agent-testweb/agentsdk-asnc-testweb/README.md b/agent-testweb/agentsdk-asnc-testweb/README.md new file mode 100644 index 0000000000000..cb7393c1fbdab --- /dev/null +++ b/agent-testweb/agentsdk-asnc-testweb/README.md @@ -0,0 +1,16 @@ + +## Install +``` +$ mvnw -P pinpoint-agentsdk-async-testweb install -Dmaven.test.skip=true +``` + +## Run +``` +$ mvnw -P pinpoint-agentsdk-async-testweb spring-boot:start +``` +You can then access here: http://localhost:18080/ + +## Stop +``` +$ mvnw -P pinpoint-agentsdk-async-testweb spring-boot:stop +``` diff --git a/agent-testweb/agentsdk-asnc-testweb/pom.xml b/agent-testweb/agentsdk-asnc-testweb/pom.xml new file mode 100644 index 0000000000000..c5275c3ac5b1f --- /dev/null +++ b/agent-testweb/agentsdk-asnc-testweb/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + + com.navercorp.pinpoint + pinpoint-agent-testweb + 2.3.0-SNAPSHOT + + + pinpoint-agentsdk-async-testweb + + jar + + + + ${pinpoint.agent.default.jvmargument} + + + + + + com.navercorp.pinpoint + pinpoint-agent-sdk + ${project.version} + + + + \ No newline at end of file diff --git a/agent-testweb/agentsdk-asnc-testweb/src/main/java/com/pinpointest/plugin/SdkAsyncPluginTestStarter.java b/agent-testweb/agentsdk-asnc-testweb/src/main/java/com/pinpointest/plugin/SdkAsyncPluginTestStarter.java new file mode 100644 index 0000000000000..747a726aa501c --- /dev/null +++ b/agent-testweb/agentsdk-asnc-testweb/src/main/java/com/pinpointest/plugin/SdkAsyncPluginTestStarter.java @@ -0,0 +1,12 @@ +package com.pinpointest.plugin; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SdkAsyncPluginTestStarter { + + public static void main(String[] args) { + SpringApplication.run(SdkAsyncPluginTestStarter.class, args); + } +} diff --git a/agent-testweb/agentsdk-asnc-testweb/src/main/java/com/pinpointest/plugin/controller/ThreadContextPropagationController.java b/agent-testweb/agentsdk-asnc-testweb/src/main/java/com/pinpointest/plugin/controller/ThreadContextPropagationController.java new file mode 100644 index 0000000000000..add7a3a138570 --- /dev/null +++ b/agent-testweb/agentsdk-asnc-testweb/src/main/java/com/pinpointest/plugin/controller/ThreadContextPropagationController.java @@ -0,0 +1,72 @@ +package com.pinpointest.plugin.controller; + +import com.navercorp.pinpoint.sdk.v1.concurrent.TraceExecutors; +import com.navercorp.pinpoint.sdk.v1.concurrent.TraceRunnable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.PreDestroy; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +@RestController +public class ThreadContextPropagationController { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final ExecutorService traceExecutor = TraceExecutors.wrapExecutorService(Executors.newSingleThreadExecutor()); + + @GetMapping(value = "/sdk-async-plugin/manual-context-propagation") + public String manualWrapExecute() throws InterruptedException, ExecutionException { + CompletableFuture future = new CompletableFuture<>(); + + traceExecutor.execute(TraceRunnable.wrap(() -> future.complete("manual-execute"))); + + sleep(1000); + + return future.get(); + } + + private final ExecutorService contextPropagationExecutor = TraceExecutors.wrapExecutorService(Executors.newSingleThreadExecutor(), true); + + @GetMapping(value = "/sdk-async-plugin/auto-context-propagation") + public String autoWrapExecute() throws InterruptedException, ExecutionException { + CompletableFuture future = new CompletableFuture<>(); + + contextPropagationExecutor.execute(() -> future.complete("auto-execute")); + + sleep(1000); + + return future.get(); + } + + private final ExecutorService executor = Executors.newSingleThreadExecutor(); + + @GetMapping(value = "/sdk-async-plugin/traceRunnable-propagation") + public String traceRunnableExecute() throws InterruptedException, ExecutionException { + CompletableFuture future = new CompletableFuture<>(); + + executor.execute(TraceRunnable.wrapAndExecute(() -> future.complete("manual-execute"))); + + sleep(1000); + + return future.get(); + } + + private void sleep(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + @PreDestroy + private void shutdown() { + this.traceExecutor.shutdown(); + this.contextPropagationExecutor.shutdown(); + } +} diff --git a/agent-testweb/agentsdk-asnc-testweb/src/main/resources/application.yml b/agent-testweb/agentsdk-asnc-testweb/src/main/resources/application.yml new file mode 100644 index 0000000000000..2416cb576dc94 --- /dev/null +++ b/agent-testweb/agentsdk-asnc-testweb/src/main/resources/application.yml @@ -0,0 +1,12 @@ +# Defined in commandlineArgument of agent-test pom.xml + +#server: +# port: 18080 + +#logging: +# level: +# root: info + +#springdoc: +# swagger-ui: +# path: / \ No newline at end of file diff --git a/agent-testweb/pom.xml b/agent-testweb/pom.xml index 2200186e5e0eb..4151bb5728d3e 100644 --- a/agent-testweb/pom.xml +++ b/agent-testweb/pom.xml @@ -51,6 +51,7 @@ + agentsdk-asnc-testweb thread-plugin-testweb paho-mqtt-plugin-testweb reactor-netty-plugin-testweb diff --git a/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/transformer/TransformTemplate.java b/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/transformer/TransformTemplate.java index fa9b9221dca2f..6194cb7f05626 100644 --- a/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/transformer/TransformTemplate.java +++ b/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/transformer/TransformTemplate.java @@ -85,8 +85,6 @@ public void transform(String className, Class trans Objects.requireNonNull(className, "className"); Objects.requireNonNull(transformCallbackClass, "transformCallbackClass"); - - TransformCallbackChecker.validate(transformCallbackClass, parameterTypes); if (ParameterUtils.hasNull(parameterTypes)) { throw new IllegalArgumentException("null parameterType not supported"); diff --git a/plugins/agentsdk-async/pom.xml b/plugins/agentsdk-async/pom.xml new file mode 100644 index 0000000000000..e893b2468efb2 --- /dev/null +++ b/plugins/agentsdk-async/pom.xml @@ -0,0 +1,24 @@ + + + + + com.navercorp.pinpoint + pinpoint-plugins + 2.3.0-SNAPSHOT + + + 4.0.0 + pinpoint-agentsdk-async-plugin + jar + + + + com.navercorp.pinpoint + pinpoint-bootstrap-core + provided + + + + + diff --git a/plugins/agentsdk-async/src/main/java/com/navercorp/pinpoint/plugin/sdk/AgentSdkAsyncConfig.java b/plugins/agentsdk-async/src/main/java/com/navercorp/pinpoint/plugin/sdk/AgentSdkAsyncConfig.java new file mode 100644 index 0000000000000..9b6844017ceb6 --- /dev/null +++ b/plugins/agentsdk-async/src/main/java/com/navercorp/pinpoint/plugin/sdk/AgentSdkAsyncConfig.java @@ -0,0 +1,41 @@ +/* + * Copyright 2021 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.sdk; + +import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; + +public class AgentSdkAsyncConfig { + + private final boolean enable; + + + public AgentSdkAsyncConfig(ProfilerConfig config) { + this.enable = config.readBoolean("profiler.agentsdk.enable", true); + } + + public boolean isEnable() { + return enable; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("AgentSdkConfig{"); + sb.append("enable=").append(enable); + sb.append('}'); + return sb.toString(); + } +} diff --git a/plugins/agentsdk-async/src/main/java/com/navercorp/pinpoint/plugin/sdk/AgentSdkAsyncConstants.java b/plugins/agentsdk-async/src/main/java/com/navercorp/pinpoint/plugin/sdk/AgentSdkAsyncConstants.java new file mode 100644 index 0000000000000..86051f32f052e --- /dev/null +++ b/plugins/agentsdk-async/src/main/java/com/navercorp/pinpoint/plugin/sdk/AgentSdkAsyncConstants.java @@ -0,0 +1,25 @@ +/* + * Copyright 2021 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.sdk; + +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; + +public class AgentSdkAsyncConstants { + public static final ServiceType THREAD_POOL_EXECUTOR = ServiceTypeFactory.of(5081, "THREAD_POOL_EXECUTOR", "THREAD_POOL_EXECUTOR"); + public static final String THREAD_POOL_EXECUTOR_SCOPE = "ThreadPoolExecutorScope"; +} diff --git a/plugins/agentsdk-async/src/main/java/com/navercorp/pinpoint/plugin/sdk/AgentSdkAsyncPlugin.java b/plugins/agentsdk-async/src/main/java/com/navercorp/pinpoint/plugin/sdk/AgentSdkAsyncPlugin.java new file mode 100644 index 0000000000000..2a4fe4ac90c81 --- /dev/null +++ b/plugins/agentsdk-async/src/main/java/com/navercorp/pinpoint/plugin/sdk/AgentSdkAsyncPlugin.java @@ -0,0 +1,136 @@ +/* + * Copyright 2021 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.sdk; + +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; +import com.navercorp.pinpoint.bootstrap.instrument.Instrumentor; +import com.navercorp.pinpoint.bootstrap.instrument.MethodFilters; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformCallback; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplate; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplateAware; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +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.plugin.sdk.interceptor.TaskCallInterceptor; +import com.navercorp.pinpoint.plugin.sdk.interceptor.ThreadPoolExecutorSubmitInterceptor; + + +import java.security.ProtectionDomain; +import java.util.Objects; + +public class AgentSdkAsyncPlugin implements ProfilerPlugin, TransformTemplateAware { + private final PLogger logger = PLoggerFactory.getLogger(getClass()); + + private TransformTemplate transformTemplate; + + + @Override + public void setup(ProfilerPluginSetupContext context) { + AgentSdkAsyncConfig agentSdkAsyncConfig = new AgentSdkAsyncConfig(context.getConfig()); + if (!agentSdkAsyncConfig.isEnable()) { + logger.debug("AgentSdkAsyncConfig is disable"); + return; + } + + logger.debug("AgentSdkAsyncConfig config={}", agentSdkAsyncConfig); + + String sdkPackage = "com.navercorp.pinpoint.sdk.v1.concurrent"; + + addExecutionInterceptorTask(sdkPackage + ".TraceCallable", "call"); + addExecutionInterceptorTask(sdkPackage + ".TraceRunnable", "run"); + + + addTraceExecutor(sdkPackage + ".TraceExecutorService"); + addTraceExecutor(sdkPackage + ".TraceScheduledExecutorService"); + addTraceExecutor(sdkPackage + ".TraceExecutor"); + +// addAsyncTaskExecutor(sdkPackage + ".TraceForkJoinPool"); + + } + + + private void addExecutionInterceptorTask(final String className, final String methodName) { + Object[] parameter = {methodName}; + Class[] parameterType = {String.class}; + transformTemplate.transform(className, TraceCommandCallback.class, parameter, parameterType); + } + + public static class TraceCommandCallback implements TransformCallback { + private final String methodName; + + public TraceCommandCallback(String methodName) { + this.methodName = Objects.requireNonNull(methodName, "methodName"); + } + + @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); + target.addField(AsyncContextAccessor.class); + final InstrumentMethod callMethod = target.getDeclaredMethod(methodName); + if (callMethod != null) { + callMethod.addInterceptor(TaskCallInterceptor.class); + } + return target.toBytecode(); + } + } + + + private void addTraceExecutor(final String className) { + transformTemplate.transform(className, AsyncRunTransformCallback.class); + } + + public static class AsyncRunTransformCallback implements TransformCallback { + private final PLogger logger = PLoggerFactory.getLogger(getClass()); + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + for (InstrumentMethod m : target.getDeclaredMethods(MethodFilters.name("execute"))) { + m.addScopedInterceptor(ThreadPoolExecutorSubmitInterceptor.class, AgentSdkAsyncConstants.THREAD_POOL_EXECUTOR_SCOPE); + } + for (InstrumentMethod m : target.getDeclaredMethods(MethodFilters.name("submit"))) { + m.addScopedInterceptor(ThreadPoolExecutorSubmitInterceptor.class, AgentSdkAsyncConstants.THREAD_POOL_EXECUTOR_SCOPE); + } + for (InstrumentMethod m : target.getDeclaredMethods(MethodFilters.name("schedule"))) { + m.addScopedInterceptor(ThreadPoolExecutorSubmitInterceptor.class, AgentSdkAsyncConstants.THREAD_POOL_EXECUTOR_SCOPE); + } + for (InstrumentMethod m : target.getDeclaredMethods(MethodFilters.name("scheduleAtFixedRate"))) { + m.addScopedInterceptor(ThreadPoolExecutorSubmitInterceptor.class, AgentSdkAsyncConstants.THREAD_POOL_EXECUTOR_SCOPE); + } + for (InstrumentMethod m : target.getDeclaredMethods(MethodFilters.name("scheduleWithFixedDelay"))) { + m.addScopedInterceptor(ThreadPoolExecutorSubmitInterceptor.class, AgentSdkAsyncConstants.THREAD_POOL_EXECUTOR_SCOPE); + } +// for (InstrumentMethod m : target.getDeclaredMethods(MethodFilters.name("invokeAll"))) { +// m.addScopedInterceptor(ThreadPoolExecutorSubmitInterceptor.class, AgentSdkAsyncConstants.THREAD_POOL_EXECUTOR_SCOPE); +// } +// for (InstrumentMethod m : target.getDeclaredMethods(MethodFilters.name("invokeAny"))) { +// m.addScopedInterceptor(ThreadPoolExecutorSubmitInterceptor.class, AgentSdkAsyncConstants.THREAD_POOL_EXECUTOR_SCOPE); +// } + return target.toBytecode(); + } + } + + + @Override + public void setTransformTemplate(TransformTemplate transformTemplate) { + this.transformTemplate = transformTemplate; + } +} diff --git a/plugins/agentsdk-async/src/main/java/com/navercorp/pinpoint/plugin/sdk/AgentSdkAsyncTraceMetadataProvider.java b/plugins/agentsdk-async/src/main/java/com/navercorp/pinpoint/plugin/sdk/AgentSdkAsyncTraceMetadataProvider.java new file mode 100644 index 0000000000000..9ed121dbe35c8 --- /dev/null +++ b/plugins/agentsdk-async/src/main/java/com/navercorp/pinpoint/plugin/sdk/AgentSdkAsyncTraceMetadataProvider.java @@ -0,0 +1,27 @@ +/* + * Copyright 2021 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.sdk; + +import com.navercorp.pinpoint.common.trace.TraceMetadataProvider; +import com.navercorp.pinpoint.common.trace.TraceMetadataSetupContext; + +public class AgentSdkAsyncTraceMetadataProvider implements TraceMetadataProvider { + @Override + public void setup(TraceMetadataSetupContext context) { + context.addServiceType(AgentSdkAsyncConstants.THREAD_POOL_EXECUTOR); + } +} diff --git a/plugins/agentsdk-async/src/main/java/com/navercorp/pinpoint/plugin/sdk/interceptor/TaskCallInterceptor.java b/plugins/agentsdk-async/src/main/java/com/navercorp/pinpoint/plugin/sdk/interceptor/TaskCallInterceptor.java new file mode 100644 index 0000000000000..94d477e7a5362 --- /dev/null +++ b/plugins/agentsdk-async/src/main/java/com/navercorp/pinpoint/plugin/sdk/interceptor/TaskCallInterceptor.java @@ -0,0 +1,45 @@ +/* + * Copyright 2021 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.sdk.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.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.plugin.sdk.AgentSdkAsyncConstants; + + +public class TaskCallInterceptor extends AsyncContextSpanEventSimpleAroundInterceptor { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + public TaskCallInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { + super(traceContext, methodDescriptor); + } + + @Override + protected void doInBeforeTrace(SpanEventRecorder recorder, AsyncContext asyncContext, Object target, Object[] args) { + } + + @Override + protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + recorder.recordApi(methodDescriptor); + recorder.recordServiceType(AgentSdkAsyncConstants.THREAD_POOL_EXECUTOR); + recorder.recordException(throwable); + } +} diff --git a/plugins/agentsdk-async/src/main/java/com/navercorp/pinpoint/plugin/sdk/interceptor/ThreadPoolExecutorSubmitInterceptor.java b/plugins/agentsdk-async/src/main/java/com/navercorp/pinpoint/plugin/sdk/interceptor/ThreadPoolExecutorSubmitInterceptor.java new file mode 100644 index 0000000000000..ecb733409fb77 --- /dev/null +++ b/plugins/agentsdk-async/src/main/java/com/navercorp/pinpoint/plugin/sdk/interceptor/ThreadPoolExecutorSubmitInterceptor.java @@ -0,0 +1,102 @@ +/* + * Copyright 2021 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.sdk.interceptor; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; +import com.navercorp.pinpoint.bootstrap.context.*; +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.plugin.sdk.AgentSdkAsyncConstants; + +public class ThreadPoolExecutorSubmitInterceptor implements AroundInterceptor { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private TraceContext traceContext; + private MethodDescriptor descriptor; + + public ThreadPoolExecutorSubmitInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + this.traceContext = traceContext; + this.descriptor = descriptor; + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + final Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + + final SpanEventRecorder recorder = trace.traceBlockBegin(); + + + boolean r = validate(args); + if (r) { + // make asynchronous trace-id + final AsyncContext asyncContext = recorder.recordNextAsyncContext(); + ((AsyncContextAccessor) args[0])._$PINPOINT$_setAsyncContext(asyncContext); + if (isDebug) { + logger.debug("Set asyncContext {}", asyncContext); + } + } + } + + private boolean validate(final Object[] args) { + if (args == null || args.length < 1) { + if (isDebug) { + logger.debug("Invalid args object. args={}.", args); + } + return false; + } + + if (!(args[0] instanceof AsyncContextAccessor)) { + if (isDebug) { + logger.debug("Invalid args[0] object. Need metadata accessor({}).", AsyncContextAccessor.class.getName()); + } + return false; + } + + return true; + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + + final Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + + try { + final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + recorder.recordApi(this.descriptor); + recorder.recordServiceType(AgentSdkAsyncConstants.THREAD_POOL_EXECUTOR); + recorder.recordException(throwable); + } finally { + trace.traceBlockEnd(); + } + } +} diff --git a/plugins/agentsdk-async/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin b/plugins/agentsdk-async/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin new file mode 100644 index 0000000000000..65b88a04d7be5 --- /dev/null +++ b/plugins/agentsdk-async/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin @@ -0,0 +1 @@ +com.navercorp.pinpoint.plugin.sdk.AgentSdkAsyncPlugin diff --git a/plugins/agentsdk-async/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider b/plugins/agentsdk-async/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider new file mode 100644 index 0000000000000..f738c758e93f7 --- /dev/null +++ b/plugins/agentsdk-async/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider @@ -0,0 +1 @@ +#com.navercorp.pinpoint.plugin.sdk.AgentSdkAsyncTraceMetadataProvider \ No newline at end of file diff --git a/plugins/assembly/pom.xml b/plugins/assembly/pom.xml index aab90598439c5..0897f71289dbd 100644 --- a/plugins/assembly/pom.xml +++ b/plugins/assembly/pom.xml @@ -367,6 +367,12 @@ ${project.version} + + com.navercorp.pinpoint + pinpoint-agentsdk-async-plugin + ${project.version} + + com.navercorp.pinpoint pinpoint-process-plugin diff --git a/plugins/pom.xml b/plugins/pom.xml index 425778d3267f8..62fa5c26ec49b 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -106,6 +106,7 @@ process paho-mqtt rocketmq + agentsdk-async diff --git a/pom.xml b/pom.xml index 78051804e6678..91ca6a10692bc 100644 --- a/pom.xml +++ b/pom.xml @@ -69,6 +69,7 @@ testcase batch report + agent-sdk diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMClass.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMClass.java index 8d7343b1be3d6..7cf9050365a41 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMClass.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMClass.java @@ -77,6 +77,9 @@ public ASMClass(EngineComponent engineComponent, final InstrumentContext pluginC this.classNode = Objects.requireNonNull(classNode, "classNode"); } + public void test() { + + } public ClassLoader getClassLoader() { return this.classNode.getClassLoader(); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/transformer/PinpointClassFilter.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/transformer/PinpointClassFilter.java index 75462448ca566..21ce977d07a4c 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/transformer/PinpointClassFilter.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/transformer/PinpointClassFilter.java @@ -17,13 +17,26 @@ package com.navercorp.pinpoint.profiler.transformer; import java.security.ProtectionDomain; +import java.util.Objects; /** * @author emeroad */ public class PinpointClassFilter implements ClassFileFilter { + private static final String DEFAULT_PACKAGE = "com/navercorp/pinpoint/"; + private static final String[] DEFAULT_EXCLUDES = {"web/", "sdk/"}; + + private final String basePackage; + private final String[] excludes; + public PinpointClassFilter() { + this(DEFAULT_PACKAGE, DEFAULT_EXCLUDES); + } + + public PinpointClassFilter(String basePackage, String[] excludes) { + this.basePackage = Objects.requireNonNull(basePackage, "basePackage"); + this.excludes = Objects.requireNonNull(excludes, "excludes"); } @Override @@ -33,9 +46,11 @@ public boolean accept(ClassLoader classLoader, String className, Class classB } // Skip pinpoint packages too. - if (className.startsWith("com/navercorp/pinpoint/")) { - if (className.startsWith("com/navercorp/pinpoint/web/")) { - return CONTINUE; + if (className.startsWith(basePackage)) { + for (String exclude : excludes) { + if (className.startsWith(exclude, basePackage.length())) { + return CONTINUE; + } } return SKIP; } diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/transformer/PinpointClassFilterTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/transformer/PinpointClassFilterTest.java index 38fdc292e6b92..bf806465ded58 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/transformer/PinpointClassFilterTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/transformer/PinpointClassFilterTest.java @@ -16,30 +16,38 @@ package com.navercorp.pinpoint.profiler.transformer; -import com.navercorp.pinpoint.common.util.ClassLoaderUtils; import org.junit.Assert; import org.junit.Test; -import java.net.URL; -import java.net.URLClassLoader; - /** * @author Woonduk Kang(emeroad) */ public class PinpointClassFilterTest { + @Test - public void testDoFilter_Package() throws Exception { + public void doFilter() throws Exception { + + ClassFileFilter filter = new PinpointClassFilter(); + + Assert.assertEquals(ClassFileFilter.CONTINUE, filter.accept(null, "java/test", null, null, null)); + Assert.assertEquals(ClassFileFilter.CONTINUE, filter.accept(null, "javax/test", null, null, null)); + Assert.assertEquals(ClassFileFilter.CONTINUE, filter.accept(null, "test", null, null, null)); + } + @Test + public void doFilter_Package() throws Exception { - final URLClassLoader agentClassLoader = new URLClassLoader(new URL[0]); ClassFileFilter filter = new PinpointClassFilter(); - final ClassLoader defaultClassLoader = ClassLoaderUtils.getDefaultClassLoader(); + Assert.assertEquals(ClassFileFilter.SKIP, filter.accept(null, "com/navercorp/pinpoint/", null, null, null)); + } + + @Test + public void doFilter_Package_exclude() throws Exception { + + ClassFileFilter filter = new PinpointClassFilter(); - Assert.assertSame("pinpoint", filter.accept(defaultClassLoader, "com/navercorp/pinpoint/", null, null, null), ClassFileFilter.SKIP); + Assert.assertEquals(ClassFileFilter.CONTINUE, filter.accept(null, "com/navercorp/pinpoint/web/", null, null, null)); - Assert.assertSame(filter.accept(defaultClassLoader, "java/test", null, null, null), ClassFileFilter.CONTINUE); - Assert.assertSame(filter.accept(defaultClassLoader, "javax/test", null, null, null), ClassFileFilter.CONTINUE); - Assert.assertSame(filter.accept(defaultClassLoader, "test", null, null, null), ClassFileFilter.CONTINUE); } -} +} \ No newline at end of file