diff --git a/.github/workflows/plugins-test.3.yaml b/.github/workflows/plugins-test.3.yaml
index 8fce605da..0629de603 100644
--- a/.github/workflows/plugins-test.3.yaml
+++ b/.github/workflows/plugins-test.3.yaml
@@ -68,6 +68,7 @@ jobs:
- vertx-web-3.54minus-scenario
- vertx-web-3.6plus-scenario
- mariadb-scenario
+ - micronaut-http-scenario
- quasar-scenario
- baidu-brpc-scenario
- retransform-class-scenario
diff --git a/CHANGES.md b/CHANGES.md
index 20e0b3516..3cf412f66 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -17,6 +17,7 @@ Release Notes.
* Fix race condition causing agent to not reconnect after network error
* Force the injected high-priority classes in order to avoid NoClassDefFoundError.
* Plugin to support xxl-job 2.3.x.
+* Add plugin to support Micronaut(HTTP Client/Server) 3.2.x-3.6.x
#### Documentation
diff --git a/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java b/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java
index c3671ff69..23d7f9f1d 100755
--- a/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java
+++ b/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java
@@ -224,4 +224,7 @@ public class ComponentsDefine {
public static final OfficialComponent APACHE_SHENYU = new OfficialComponent(127, "Apache-ShenYu");
public static final OfficialComponent HUTOOL = new OfficialComponent(128, "Hutool");
+
+ public static final OfficialComponent MICRONAUT = new OfficialComponent(131, "Micronaut");
+
}
diff --git a/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-client-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-client-plugin/pom.xml
new file mode 100644
index 000000000..1fb5f2804
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-client-plugin/pom.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+ org.apache.skywalking
+ micronaut-plugins
+ 8.12.0-SNAPSHOT
+
+ 4.0.0
+
+ micronaut-http-client-plugin
+
+
+ 8
+ 8
+
+
+
+
+ io.projectreactor
+ reactor-core
+ 3.4.21
+ provided
+
+
+
+ io.micronaut
+ micronaut-http-client
+ 3.6.0
+ provided
+
+
+
+
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-client-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/client/BuildExchangeStreamPublisherInterceptor.java b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-client-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/client/BuildExchangeStreamPublisherInterceptor.java
new file mode 100644
index 000000000..0eb23c51e
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-client-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/client/BuildExchangeStreamPublisherInterceptor.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.micronaut.http.client;
+
+import io.micronaut.http.HttpResponse;
+import io.micronaut.http.MutableHttpRequest;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.reactivestreams.Publisher;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.util.function.Function;
+import static org.apache.skywalking.apm.plugin.micronaut.http.client.MicronautCommons.beginTrace;
+import static org.apache.skywalking.apm.plugin.micronaut.http.client.MicronautCommons.buildTracePublisher;
+import static org.apache.skywalking.apm.plugin.micronaut.http.client.MicronautCommons.finish;
+
+public class BuildExchangeStreamPublisherInterceptor implements InstanceMethodsAroundInterceptor {
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret) throws Throwable {
+ MutableHttpRequest> request = (MutableHttpRequest) allArguments[1];
+ Function>> function = (Function>>) ret;
+ return (Function>>) uri -> {
+ beginTrace(request, uri);
+ return buildTracePublisher(request, function.apply(uri));
+ };
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t) {
+ MutableHttpRequest> request = (MutableHttpRequest) allArguments[1];
+ finish(request, span -> span.log(t).errorOccurred());
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-client-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/client/ExchangeImplInterceptor.java b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-client-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/client/ExchangeImplInterceptor.java
new file mode 100644
index 000000000..eb8dd1bcb
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-client-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/client/ExchangeImplInterceptor.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.micronaut.http.client;
+
+import io.micronaut.http.HttpResponse;
+import io.micronaut.http.MutableHttpRequest;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.reactivestreams.Publisher;
+
+import java.lang.reflect.Method;
+import java.net.URI;
+
+import static org.apache.skywalking.apm.plugin.micronaut.http.client.MicronautCommons.finish;
+import static org.apache.skywalking.apm.plugin.micronaut.http.client.MicronautCommons.buildTracePublisher;
+import static org.apache.skywalking.apm.plugin.micronaut.http.client.MicronautCommons.beginTrace;
+
+public class ExchangeImplInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+ MutableHttpRequest> request = (MutableHttpRequest>) allArguments[2];
+ URI requestURI = (URI) allArguments[0];
+ beginTrace(request, requestURI);
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret) throws Throwable {
+ MutableHttpRequest> request = (MutableHttpRequest>) allArguments[2];
+ Publisher> retPublisher = (Publisher>) ret;
+ return buildTracePublisher(request, retPublisher);
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t) {
+ finish((MutableHttpRequest>) allArguments[0], span -> span.errorOccurred().log(t));
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-client-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/client/MicronautCommons.java b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-client-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/client/MicronautCommons.java
new file mode 100644
index 000000000..e71d5b1e8
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-client-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/client/MicronautCommons.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.micronaut.http.client;
+
+import io.micronaut.http.HttpResponse;
+import io.micronaut.http.MutableHttpRequest;
+import io.micronaut.http.context.ServerRequestContext;
+import org.apache.skywalking.apm.agent.core.context.CarrierItem;
+import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.tag.Tags;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.util.StringUtil;
+import org.reactivestreams.Publisher;
+import reactor.core.publisher.Flux;
+
+import java.net.URI;
+import java.util.function.Consumer;
+
+public class MicronautCommons {
+
+ private static final String SPAN_KEY = "CORS_SPAN";
+ private static final String SKY_CONTEXT_SNAPSHOT_KEY = "CORS_SNAPSHOT";
+
+ static void beginTrace(MutableHttpRequest> request, URI requestURI) {
+ String requestMethod = request.getMethod().name();
+ AbstractSpan span = ContextManager.createExitSpan(requestMethod + ":" + request.getPath(), requestURI.getHost() + ":" + requestURI.getPort());
+ //The key is set in micronaut-http-server-plugin . See org.apache.skywalking.apm.plugin.micronaut.http.server#beginTrace
+ ServerRequestContext.currentRequest().flatMap(req -> req.getAttribute(SKY_CONTEXT_SNAPSHOT_KEY)).ifPresent(e -> ContextManager.continued((ContextSnapshot) e));
+ final ContextCarrier contextCarrier = new ContextCarrier();
+ ContextManager.inject(contextCarrier);
+ span.setComponent(ComponentsDefine.MICRONAUT);
+ Tags.HTTP.METHOD.set(span, requestMethod);
+ Tags.URL.set(span, String.format("%s://%s:%s%s", requestURI.getScheme(), requestURI.getHost(), requestURI.getPort(), requestURI.getPath()));
+ SpanLayer.asHttp(span);
+ CarrierItem next = contextCarrier.items();
+ while (next.hasNext()) {
+ next = next.next();
+ request.header(next.getHeadKey(), next.getHeadValue());
+ }
+ span.prepareForAsync();
+ ContextManager.stopSpan(span);
+ request.setAttribute(SPAN_KEY, span);
+ if (MicronautHttpClientPluginConfig.Plugin.MicronautHttpClient.COLLECT_HTTP_PARAMS) {
+ collectHttpParam(request, span);
+ }
+ }
+
+ static Publisher extends HttpResponse>> buildTracePublisher(MutableHttpRequest> request, Publisher extends HttpResponse>> retPublisher) {
+ return Flux.from(retPublisher).doOnError(ex -> finish(request, span -> span.log(ex).errorOccurred()))
+ .doOnNext(resp ->
+ finish(request, span -> {
+ Tags.HTTP_RESPONSE_STATUS_CODE.set(span, resp.code());
+ if (resp.code() >= 400) {
+ span.errorOccurred();
+ }
+ //Activate HTTP parameters collecting automatically in the profiling context.
+ if (!MicronautHttpClientPluginConfig.Plugin.MicronautHttpClient.COLLECT_HTTP_PARAMS && span.isProfiling()) {
+ collectHttpParam(request, span);
+ }
+ })
+ );
+ }
+
+ static void collectHttpParam(MutableHttpRequest> httpRequest, AbstractSpan span) {
+ String tag = httpRequest.getUri().getQuery();
+ tag = MicronautHttpClientPluginConfig.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD > 0 ?
+ StringUtil.cut(tag, MicronautHttpClientPluginConfig.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD) : tag;
+ if (StringUtil.isNotEmpty(tag)) {
+ Tags.HTTP.PARAMS.set(span, tag);
+ }
+ }
+
+ static void finish(MutableHttpRequest> request, Consumer action) {
+ try {
+ request.getAttribute(SPAN_KEY)
+ .map(span -> (AbstractSpan) span)
+ .ifPresent(span -> {
+ action.accept(span);
+ span.asyncFinish();
+ });
+ } finally {
+ request.removeAttribute(SPAN_KEY, AbstractSpan.class);
+ }
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-client-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/client/MicronautHttpClientPluginConfig.java b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-client-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/client/MicronautHttpClientPluginConfig.java
new file mode 100644
index 000000000..54f3aca77
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-client-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/client/MicronautHttpClientPluginConfig.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.micronaut.http.client;
+
+import org.apache.skywalking.apm.agent.core.boot.PluginConfig;
+
+public class MicronautHttpClientPluginConfig {
+
+ public static class Plugin {
+ @PluginConfig(root = MicronautHttpClientPluginConfig.class)
+ public static class MicronautHttpClient {
+ /**
+ * This config item controls that whether the HttpClient plugin should collect the parameters of the request.
+ */
+ public static boolean COLLECT_HTTP_PARAMS = false;
+ }
+
+ @PluginConfig(root = MicronautHttpClientPluginConfig.class)
+ public static class Http {
+ /**
+ * When either {@link MicronautHttpClient#COLLECT_HTTP_PARAMS} is enabled, how many characters to keep and send to the
+ * OAP backend, use negative values to keep and send the complete parameters, NB. this config item is added
+ * for the sake of performance
+ */
+ public static int HTTP_PARAMS_LENGTH_THRESHOLD = 1024;
+ }
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-client-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/client/define/MicronautClientInstrumentation.java b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-client-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/client/define/MicronautClientInstrumentation.java
new file mode 100644
index 000000000..202a75b65
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-client-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/client/define/MicronautClientInstrumentation.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.micronaut.http.client.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
+import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
+
+public class MicronautClientInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "io.micronaut.http.client.netty.DefaultHttpClient";
+ private static final String CLIENT_EXCHANGE_INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.micronaut.http.client.ExchangeImplInterceptor";
+ private static final String STREAM_EXCHANGE_INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.micronaut.http.client.BuildExchangeStreamPublisherInterceptor";
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[]{
+ new InstanceMethodsInterceptPoint() {
+ //microaut 3.4.4-3.6.x (As of now, the latest version is 3.6.0)
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("exchangeImpl").and(takesArguments(5));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return CLIENT_EXCHANGE_INTERCEPT_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ },
+ // microaut 3.2.0-3.4.3
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("buildExchangePublisher").and(takesArguments(4));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return STREAM_EXCHANGE_INTERCEPT_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return byName(ENHANCE_CLASS);
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-client-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-client-plugin/src/main/resources/skywalking-plugin.def
new file mode 100644
index 000000000..560b24df1
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-client-plugin/src/main/resources/skywalking-plugin.def
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+
+micronaut-http-client-3.2.x-3.6.x=org.apache.skywalking.apm.plugin.micronaut.http.client.define.MicronautClientInstrumentation
diff --git a/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/pom.xml
new file mode 100644
index 000000000..4b282e46f
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/pom.xml
@@ -0,0 +1,55 @@
+
+
+
+
+
+ org.apache.skywalking
+ micronaut-plugins
+ 8.12.0-SNAPSHOT
+
+ 4.0.0
+
+ micronaut-http-server-plugin
+ jar
+
+
+ 8
+ 8
+
+
+
+
+ io.micronaut
+ micronaut-http
+ 3.6.0
+ provided
+
+
+
+ io.micronaut
+ micronaut-http-server-netty
+ 3.6.0
+ provided
+
+
+
+
+
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/server/HandleStatusErrorInterceptor.java b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/server/HandleStatusErrorInterceptor.java
new file mode 100644
index 000000000..094c2d108
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/server/HandleStatusErrorInterceptor.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.micronaut.http.server;
+
+import io.micronaut.http.server.netty.NettyHttpRequest;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+
+import java.lang.reflect.Method;
+
+import static org.apache.skywalking.apm.plugin.micronaut.http.server.MicronautCommons.cleanup;
+import static org.apache.skywalking.apm.plugin.micronaut.http.server.MicronautCommons.beginTrace;
+
+public class HandleStatusErrorInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+ beginTrace((NettyHttpRequest>) allArguments[1]);
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret) throws Throwable {
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t) {
+ cleanup((NettyHttpRequest>) allArguments[1]);
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/server/MicronautCommons.java b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/server/MicronautCommons.java
new file mode 100644
index 000000000..f3b24f769
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/server/MicronautCommons.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.micronaut.http.server;
+
+import io.micronaut.http.HttpRequest;
+import org.apache.skywalking.apm.agent.core.context.CarrierItem;
+import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.tag.Tags;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.util.StringUtil;
+
+class MicronautCommons {
+ static final String SPAN_KEY = "CORS_SPAN";
+ static final String SKY_CONTEXT_SNAPSHOT_KEY = "CORS_SNAPSHOT";
+
+ static void collectHttpParam(HttpRequest> httpRequest, AbstractSpan span) {
+ String tag = httpRequest.getUri().getQuery();
+ tag = MicronautHttpServerPluginConfig.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD > 0 ?
+ StringUtil.cut(tag, MicronautHttpServerPluginConfig.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD) : tag;
+ if (StringUtil.isNotEmpty(tag)) {
+ Tags.HTTP.PARAMS.set(span, tag);
+ }
+ }
+
+ static void cleanup(HttpRequest> request) {
+ request.removeAttribute(MicronautCommons.SKY_CONTEXT_SNAPSHOT_KEY, ContextSnapshot.class);
+ request.removeAttribute(MicronautCommons.SPAN_KEY, AbstractSpan.class);
+ }
+
+ static void beginTrace(HttpRequest> request) {
+ ContextCarrier contextCarrier = new ContextCarrier();
+ CarrierItem next = contextCarrier.items();
+ while (next.hasNext()) {
+ next = next.next();
+ next.setHeadValue(request.getHeaders().get(next.getHeadKey()));
+ }
+ String operationName = String.join(":", request.getMethod(), request.getPath());
+ AbstractSpan span = ContextManager.createEntrySpan(operationName, contextCarrier);
+ ContextSnapshot capture = ContextManager.capture();
+ request.setAttribute(SPAN_KEY, span);
+ request.setAttribute(SKY_CONTEXT_SNAPSHOT_KEY, capture);
+ Tags.URL.set(span, String.format("%s://%s:%s%s", request.isSecure() ? "https" : "http", request.getServerName(), request.getServerAddress().getPort(), request.getUri().getPath()));
+ Tags.HTTP.METHOD.set(span, request.getMethodName());
+ span.setComponent(ComponentsDefine.MICRONAUT);
+ SpanLayer.asHttp(span);
+ span.prepareForAsync();
+ ContextManager.stopSpan(span);
+ if (MicronautHttpServerPluginConfig.Plugin.MicronautHttpServer.COLLECT_HTTP_PARAMS) {
+ collectHttpParam(request, span);
+ }
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/server/MicronautHttpServerPluginConfig.java b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/server/MicronautHttpServerPluginConfig.java
new file mode 100644
index 000000000..5abbf2227
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/server/MicronautHttpServerPluginConfig.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.micronaut.http.server;
+
+import org.apache.skywalking.apm.agent.core.boot.PluginConfig;
+
+public class MicronautHttpServerPluginConfig {
+
+ public static class Plugin {
+ @PluginConfig(root = MicronautHttpServerPluginConfig.class)
+ public static class MicronautHttpServer {
+ /**
+ * This config item controls that whether the Http plugin should collect the parameters of the request.
+ */
+ public static boolean COLLECT_HTTP_PARAMS = false;
+ }
+
+ @PluginConfig(root = MicronautHttpServerPluginConfig.class)
+ public static class Http {
+ /**
+ * When either {@link MicronautHttpServer#COLLECT_HTTP_PARAMS} is enabled, how many characters to keep and send to the
+ * OAP backend, use negative values to keep and send the complete parameters, NB. this config item is added
+ * for the sake of performance
+ */
+ public static int HTTP_PARAMS_LENGTH_THRESHOLD = 1024;
+ }
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/server/RouteMatchExecuteInterceptor.java b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/server/RouteMatchExecuteInterceptor.java
new file mode 100644
index 000000000..4f4891857
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/server/RouteMatchExecuteInterceptor.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.micronaut.http.server;
+
+import io.micronaut.http.context.ServerRequestContext;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+
+import java.lang.reflect.Method;
+
+public class RouteMatchExecuteInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+ ServerRequestContext.currentRequest().ifPresent(MicronautCommons::beginTrace);
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret) throws Throwable {
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t) {
+ ServerRequestContext.currentRequest().ifPresent(MicronautCommons::cleanup);
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/server/WriteFinalNettyResponseInterceptor.java b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/server/WriteFinalNettyResponseInterceptor.java
new file mode 100644
index 000000000..f6b9113f8
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/server/WriteFinalNettyResponseInterceptor.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.micronaut.http.server;
+
+import io.micronaut.http.HttpRequest;
+import io.micronaut.http.MutableHttpResponse;
+import org.apache.skywalking.apm.agent.core.context.tag.Tags;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+
+import java.lang.reflect.Method;
+
+import static org.apache.skywalking.apm.plugin.micronaut.http.server.MicronautCommons.cleanup;
+import static org.apache.skywalking.apm.plugin.micronaut.http.server.MicronautCommons.collectHttpParam;
+
+public class WriteFinalNettyResponseInterceptor implements InstanceMethodsAroundInterceptor {
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Object ret) throws Throwable {
+ MutableHttpResponse> message = (MutableHttpResponse>) allArguments[0];
+ HttpRequest> request = (HttpRequest>) allArguments[1];
+ request.getAttribute(MicronautCommons.SPAN_KEY)
+ .map(span -> (AbstractSpan) span)
+ .ifPresent(span -> {
+ int code = message.status().getCode();
+ Tags.HTTP_RESPONSE_STATUS_CODE.set(span, code);
+ if (code >= 400) {
+ span.errorOccurred();
+ }
+ //Activate HTTP parameters collecting automatically in the profiling context.
+ if (!MicronautHttpServerPluginConfig.Plugin.MicronautHttpServer.COLLECT_HTTP_PARAMS && span.isProfiling()) {
+ collectHttpParam((HttpRequest>) allArguments[1], span);
+ }
+ span.asyncFinish();
+ });
+ cleanup(request);
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes, Throwable t) {
+ cleanup((HttpRequest>) allArguments[1]);
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/server/define/RouteMatchInstrumentation.java b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/server/define/RouteMatchInstrumentation.java
new file mode 100644
index 000000000..ff8445556
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/server/define/RouteMatchInstrumentation.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.micronaut.http.server.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
+import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
+
+public class RouteMatchInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String EXECUTE_INTERCEPTOR = "org.apache.skywalking.apm.plugin.micronaut.http.server.RouteMatchExecuteInterceptor";
+
+ private static final String ROUTE_MATCH_CLASS_NAME = "io.micronaut.web.router.AbstractRouteMatch";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return byName(ROUTE_MATCH_CLASS_NAME);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[]{
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("execute").and(takesArguments(1));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return EXECUTE_INTERCEPTOR;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/server/define/RoutingInBoundHandlerInstrumentation.java b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/server/define/RoutingInBoundHandlerInstrumentation.java
new file mode 100644
index 000000000..3eef57aea
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/micronaut/http/server/define/RoutingInBoundHandlerInstrumentation.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.micronaut.http.server.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
+import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
+
+public class RoutingInBoundHandlerInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String CLASS_NAME = "io.micronaut.http.server.netty.RoutingInBoundHandler";
+
+ private static final String FINAL_RESPONSE_INTERCEPTOR = "org.apache.skywalking.apm.plugin.micronaut.http.server.WriteFinalNettyResponseInterceptor";
+
+ private static final String HANDLE_ERROR_INTERCEPTOR = "org.apache.skywalking.apm.plugin.micronaut.http.server.HandleStatusErrorInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return byName(CLASS_NAME);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[]{
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("handleStatusError").and(takesArguments(4));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return HANDLE_ERROR_INTERCEPTOR;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ },
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("writeFinalNettyResponse").and(takesArguments(3));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return FINAL_RESPONSE_INTERCEPTOR;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/src/main/resources/skywalking-plugin.def
new file mode 100644
index 000000000..36bd74e91
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/micronaut-http-server-plugin/src/main/resources/skywalking-plugin.def
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+
+micronaut-http-server-3.2.x-3.6.x=org.apache.skywalking.apm.plugin.micronaut.http.server.define.RouteMatchInstrumentation
+micronaut-http-server-3.2.x-3.6.x=org.apache.skywalking.apm.plugin.micronaut.http.server.define.RoutingInBoundHandlerInstrumentation
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/micronaut-plugins/pom.xml b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/pom.xml
new file mode 100644
index 000000000..2ce0a6b9e
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/micronaut-plugins/pom.xml
@@ -0,0 +1,42 @@
+
+
+
+
+ apm-sdk-plugin
+ org.apache.skywalking
+ 8.12.0-SNAPSHOT
+
+ 4.0.0
+
+ micronaut-plugins
+ pom
+
+
+ UTF-8
+ /..
+
+
+
+ micronaut-http-server-plugin
+ micronaut-http-client-plugin
+
+
+
diff --git a/apm-sniffer/apm-sdk-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/pom.xml
index 93fabad88..538162693 100644
--- a/apm-sniffer/apm-sdk-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/pom.xml
@@ -122,6 +122,7 @@
tomcat-thread-pool-pluginguava-eventbus-pluginhutool-plugins
+ micronaut-pluginspom
diff --git a/docs/en/setup/service-agent/java-agent/Plugin-list.md b/docs/en/setup/service-agent/java-agent/Plugin-list.md
index 3029b158a..60b9c2d10 100644
--- a/docs/en/setup/service-agent/java-agent/Plugin-list.md
+++ b/docs/en/setup/service-agent/java-agent/Plugin-list.md
@@ -141,3 +141,5 @@
- shenyu-2.4.x
- jdk-threadpool-plugin
- hutool-http-5.x
+- micronaut-http-client-3.2.x-3.6.x
+- micronaut-http-server-3.2.x-3.6.x
diff --git a/docs/en/setup/service-agent/java-agent/Supported-list.md b/docs/en/setup/service-agent/java-agent/Supported-list.md
index 98cdc7658..7ac7c1826 100644
--- a/docs/en/setup/service-agent/java-agent/Supported-list.md
+++ b/docs/en/setup/service-agent/java-agent/Supported-list.md
@@ -20,6 +20,7 @@ metrics based on the tracing data.
* [Play Framework](https://www.playframework.com/) 2.6.x -> 2.8.x
* [Light4J Microservices Framework](https://doc.networknt.com/) 1.6.x -> 2.x
* [Netty SocketIO](https://github.com/mrniko/netty-socketio) 1.x
+ * [Micrinaut Http Server](https://github.com/micronaut-projects/micronaut-core) 3.2.x -> 3.6.x
* HTTP Client
* [Feign](https://github.com/OpenFeign/feign) 9.x
* [Netflix Spring Cloud Feign](https://github.com/spring-cloud/spring-cloud-openfeign) 1.1.x -> 2.x
@@ -31,6 +32,7 @@ metrics based on the tracing data.
* [AsyncHttpClient](https://github.com/AsyncHttpClient/async-http-client) 2.1+
* JRE HttpURLConnection (Optional²)
* [Hutool-http](https://www.hutool.cn/) client 5.x
+ * [Micrinaut Http Client](https://github.com/micronaut-projects/micronaut-core) 3.2.x -> 3.6.x
* HTTP Gateway
* [Spring Cloud Gateway](https://spring.io/projects/spring-cloud-gateway) 2.0.2.RELEASE -> 3.x (Optional²)
* [Apache ShenYu](https://shenyu.apache.org) (Rich protocol support: `HTTP`,`Spring Cloud`,`gRPC`,`Dubbo`,`SOFARPC`,`Motan`,`Tars`) 2.4.x (Optional²)
diff --git a/docs/en/setup/service-agent/java-agent/configurations.md b/docs/en/setup/service-agent/java-agent/configurations.md
index 54562d7ee..c729c9de1 100644
--- a/docs/en/setup/service-agent/java-agent/configurations.md
+++ b/docs/en/setup/service-agent/java-agent/configurations.md
@@ -111,6 +111,8 @@ This is the properties list supported in `agent/config/agent.config`.
| `plugin.neo4j.cypher_parameters_max_length` | If set to positive number, the `db.cypher.parameters` would be truncated to this length, otherwise it would be completely saved, which may cause performance problem. | SW_PLUGIN_NEO4J_CYPHER_PARAMETERS_MAX_LENGTH | `512` |
| `plugin.neo4j.cypher_body_max_length` | If set to positive number, the `db.statement` would be truncated to this length, otherwise it would be completely saved, which may cause performance problem. | SW_PLUGIN_NEO4J_CYPHER_BODY_MAX_LENGTH | `2048` |
| `plugin.cpupolicy.sample_cpu_usage_percent_limit` | If set to a positive number and activate `trace sampler CPU policy plugin`, the trace would not be collected when agent process CPU usage percent is greater than `plugin.cpupolicy.sample_cpu_usage_percent_limit`. | SW_SAMPLE_CPU_USAGE_PERCENT_LIMIT | `-1` |
+| `plugin.micronauthttpclient.collect_http_params` | This config item controls that whether the Micronaut http client plugin should collect the parameters of the request. Also, activate implicitly in the profiled trace. | SW_PLUGIN_MICRONAUTHTTPCLIENT_COLLECT_HTTP_PARAMS | `false` |
+| `plugin.micronauthttpserver.collect_http_params` | This config item controls that whether the Micronaut http server plugin should collect the parameters of the request. Also, activate implicitly in the profiled trace. | SW_PLUGIN_MICRONAUTHTTPSERVER_COLLECT_HTTP_PARAMS | `false` |
# Dynamic Configurations
All configurations above are static, if you need to change some agent settings at runtime, please read [CDS - Configuration Discovery Service document](configuration-discovery.md) for more details.
diff --git a/test/plugin/scenarios/micronaut-http-scenario/bin/startup.sh b/test/plugin/scenarios/micronaut-http-scenario/bin/startup.sh
new file mode 100644
index 000000000..815d657d9
--- /dev/null
+++ b/test/plugin/scenarios/micronaut-http-scenario/bin/startup.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+
+home="$(cd "$(dirname $0)"; pwd)"
+
+java -jar ${agent_opts} "-Dskywalking.agent.service_name=micronaut-scenario-8081" "-Dmicronaut.server.port=8081" "-Dskywalking.plugin.micronauthttpclient.collect_http_params=true" "-Dskywalking.plugin.micronauthttpserver.collect_http_params=true" ${home}/../libs/micronaut-http-scenario.jar &
+java -jar ${agent_opts} "-Dskywalking.agent.service_name=micronaut-scenario-8080" "-Dmicronaut.server.port=8080" "-Dskywalking.plugin.micronauthttpclient.collect_http_params=true" "-Dskywalking.plugin.micronauthttpserver.collect_http_params=true" ${home}/../libs/micronaut-http-scenario.jar &
\ No newline at end of file
diff --git a/test/plugin/scenarios/micronaut-http-scenario/config/expectedData.yaml b/test/plugin/scenarios/micronaut-http-scenario/config/expectedData.yaml
new file mode 100644
index 000000000..2530b2ba9
--- /dev/null
+++ b/test/plugin/scenarios/micronaut-http-scenario/config/expectedData.yaml
@@ -0,0 +1,191 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+
+segmentItems:
+ - serviceName: micronaut-scenario-8080
+ segmentSize: ge 4
+ segments:
+ - segmentId: not null
+ spans:
+ - operationName: GET:/micronaut/success
+ operationId: 0
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: gt 0
+ endTime: gt 0
+ componentId: 131
+ isError: false
+ spanType: Exit
+ peer: localhost:8081
+ skipAnalysis: false
+ tags:
+ - {key: http.method, value: GET}
+ - {key: url, value: 'http://localhost:8081/micronaut/success'}
+ - {key: http.params, value: a=1&b=2}
+ - {key: http.status_code, value: '200'}
+ refs:
+ - {parentEndpoint: 'GET:/micronaut/start', networkAddress: '', refType: CrossThread,
+ parentSpanId: 0, parentTraceSegmentId: not null,
+ parentServiceInstance: not null, parentService: micronaut-scenario-8080,
+ traceId: not null}
+ - segmentId: not null
+ spans:
+ - operationName: GET:/micronaut/404
+ operationId: 0
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: gt 0
+ endTime: gt 0
+ componentId: 131
+ isError: true
+ spanType: Exit
+ peer: localhost:8081
+ skipAnalysis: false
+ tags:
+ - {key: http.method, value: GET}
+ - {key: url, value: 'http://localhost:8081/micronaut/404'}
+ logs:
+ - logEvent:
+ - {key: event, value: error}
+ - {key: error.kind, value: io.micronaut.http.client.exceptions.HttpClientResponseException}
+ - {key: message, value: Not Found}
+ - {key: stack,value: not null}
+ refs:
+ - {parentEndpoint: 'GET:/micronaut/start', networkAddress: '', refType: CrossThread,
+ parentSpanId: 0, parentTraceSegmentId: not null,
+ parentServiceInstance: not null, parentService: micronaut-scenario-8080,
+ traceId: not null}
+ - segmentId: not null
+ spans:
+ - operationName: GET:/micronaut/error
+ operationId: 0
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: gt 0
+ endTime: gt 0
+ componentId: 131
+ isError: true
+ spanType: Exit
+ peer: localhost:8081
+ skipAnalysis: false
+ tags:
+ - {key: http.method, value: GET}
+ - {key: url, value: 'http://localhost:8081/micronaut/error'}
+ logs:
+ - logEvent:
+ - {key: event, value: error}
+ - {key: error.kind, value: io.micronaut.http.client.exceptions.HttpClientResponseException}
+ - {key: message, value: not null}
+ - {key: stack,value: not null}
+ refs:
+ - {parentEndpoint: 'GET:/micronaut/start', networkAddress: '', refType: CrossThread,
+ parentSpanId: 0, parentTraceSegmentId: not null,
+ parentServiceInstance: not null, parentService: micronaut-scenario-8080,
+ traceId: not null}
+ - segmentId: not null
+ spans:
+ - operationName: GET:/micronaut/start
+ operationId: 0
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: gt 0
+ endTime: gt 0
+ componentId: 131
+ isError: false
+ spanType: Entry
+ peer: ''
+ skipAnalysis: false
+ tags:
+ - {key: url, value: 'http://localhost:8080/micronaut/start'}
+ - {key: http.method, value: GET}
+ - {key: http.status_code, value: '200'}
+ - serviceName: micronaut-scenario-8081
+ segmentSize: 3
+ segments:
+ - segmentId: not null
+ spans:
+ - operationName: GET:/micronaut/success
+ operationId: 0
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: gt 0
+ endTime: gt 0
+ componentId: 131
+ isError: false
+ spanType: Entry
+ peer: ''
+ skipAnalysis: false
+ tags:
+ - {key: url, value: 'http://localhost:8081/micronaut/success'}
+ - {key: http.method, value: GET}
+ - {key: http.params, value: a=1&b=2}
+ - {key: http.status_code, value: '200'}
+ refs:
+ - {parentEndpoint: 'GET:/micronaut/success', networkAddress: 'localhost:8081',
+ refType: CrossProcess, parentSpanId: 0, parentTraceSegmentId: not null,
+ parentServiceInstance: not null, parentService: micronaut-scenario-8080,
+ traceId: not null}
+ - segmentId: not null
+ spans:
+ - operationName: GET:/micronaut/404
+ operationId: 0
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: gt 0
+ endTime: gt 0
+ componentId: 131
+ isError: true
+ spanType: Entry
+ peer: ''
+ skipAnalysis: false
+ tags:
+ - {key: url, value: 'http://localhost:8081/micronaut/404'}
+ - {key: http.method, value: GET}
+ - {key: http.status_code, value: '404'}
+ refs:
+ - {parentEndpoint: 'GET:/micronaut/404', networkAddress: 'localhost:8081', refType: CrossProcess,
+ parentSpanId: 0, parentTraceSegmentId: not null,
+ parentServiceInstance: not null, parentService: micronaut-scenario-8080,
+ traceId: not null}
+ - segmentId: not null
+ spans:
+ - operationName: GET:/micronaut/error
+ operationId: 0
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: gt 0
+ endTime: gt 0
+ componentId: 131
+ isError: true
+ spanType: Entry
+ peer: ''
+ skipAnalysis: false
+ tags:
+ - {key: url, value: 'http://localhost:8081/micronaut/error'}
+ - {key: http.method, value: GET}
+ - {key: http.status_code, value: '500'}
+ refs:
+ - {parentEndpoint: 'GET:/micronaut/error', networkAddress: 'localhost:8081',
+ refType: CrossProcess, parentSpanId: 0, parentTraceSegmentId: not null,
+ parentServiceInstance: not null, parentService: micronaut-scenario-8080,
+ traceId: not null}
\ No newline at end of file
diff --git a/test/plugin/scenarios/micronaut-http-scenario/configuration.yml b/test/plugin/scenarios/micronaut-http-scenario/configuration.yml
new file mode 100644
index 000000000..295905807
--- /dev/null
+++ b/test/plugin/scenarios/micronaut-http-scenario/configuration.yml
@@ -0,0 +1,20 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+
+type: jvm
+entryService: http://localhost:8080/micronaut/start
+healthCheck: http://localhost:8080/micronaut/healthCheck
+startScript: ./bin/startup.sh
\ No newline at end of file
diff --git a/test/plugin/scenarios/micronaut-http-scenario/pom.xml b/test/plugin/scenarios/micronaut-http-scenario/pom.xml
new file mode 100644
index 000000000..f9706e1da
--- /dev/null
+++ b/test/plugin/scenarios/micronaut-http-scenario/pom.xml
@@ -0,0 +1,226 @@
+
+
+
+ 4.0.0
+
+ org.apache.skywalking
+ micronaut-http-scenario
+ 1.0.0
+
+ jar
+ micronaut-scenario
+
+ jar
+ 1.8
+
+
+ 1.8
+ netty
+ 1.8
+ 1.8
+ org.apache.skywalking.apm.testcase.micronaut.Application
+
+
+
+
+ io.micronaut
+ micronaut-inject
+ compile
+
+
+ io.micronaut
+ micronaut-validation
+ compile
+
+
+ io.micronaut
+ micronaut-inject-groovy
+ test
+
+
+ org.spockframework
+ spock-core
+ test
+
+
+ org.codehaus.groovy
+ groovy-all
+
+
+
+
+ io.micronaut.test
+ micronaut-test-spock
+ test
+
+
+ io.micronaut
+ micronaut-http-client
+ compile
+
+
+ io.micronaut
+ micronaut-http-server-netty
+ compile
+
+
+ io.micronaut
+ micronaut-jackson-databind
+ compile
+
+
+ ch.qos.logback
+ logback-classic
+ runtime
+
+
+ io.projectreactor
+ reactor-core
+
+
+
+
+
+
+ io.micronaut
+ micronaut-bom
+ ${test.framework.version}
+ pom
+ import
+
+
+
+
+
+
+ micronaut-http-scenario
+
+
+
+ io.micronaut.build
+ micronaut-maven-plugin
+ 3.4.0
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.0.0-M7
+
+
+ **/*Spec.*
+ **/*Test.*
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.10.1
+
+
+
+ io.micronaut
+ micronaut-inject-java
+ ${test.framework.version}
+
+
+ io.micronaut
+ micronaut-http-validation
+ ${test.framework.version}
+
+
+
+ -Amicronaut.processing.group=org.apache.skywalking
+ -Amicronaut.processing.module=micronaut-http-scenario
+
+
+
+
+ org.codehaus.gmavenplus
+ gmavenplus-plugin
+ 1.13.0
+
+
+
+ addSources
+ generateStubs
+ compile
+ removeStubs
+ addTestSources
+ generateTestStubs
+ compileTests
+ removeTestStubs
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.3.0
+
+
+ default-shade
+
+ false
+
+
+ ${exec.mainClass}
+
+
+
+
+
+ package
+
+ shade
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+ assemble
+ package
+
+ single
+
+
+
+ src/main/assembly/assembly.xml
+
+ ./target/
+ false
+
+
+
+
+
+
+
diff --git a/test/plugin/scenarios/micronaut-http-scenario/src/main/assembly/assembly.xml b/test/plugin/scenarios/micronaut-http-scenario/src/main/assembly/assembly.xml
new file mode 100644
index 000000000..b969f0138
--- /dev/null
+++ b/test/plugin/scenarios/micronaut-http-scenario/src/main/assembly/assembly.xml
@@ -0,0 +1,41 @@
+
+
+
+
+ zip
+
+
+
+
+ ./bin
+ 0775
+
+
+
+
+
+ ${project.build.directory}/micronaut-http-scenario.jar
+ ./libs
+ 0775
+
+
+
diff --git a/test/plugin/scenarios/micronaut-http-scenario/src/main/java/org/apache/skywalking/apm/testcase/micronaut/Application.java b/test/plugin/scenarios/micronaut-http-scenario/src/main/java/org/apache/skywalking/apm/testcase/micronaut/Application.java
new file mode 100644
index 000000000..f30ded120
--- /dev/null
+++ b/test/plugin/scenarios/micronaut-http-scenario/src/main/java/org/apache/skywalking/apm/testcase/micronaut/Application.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.testcase.micronaut;
+
+import io.micronaut.runtime.Micronaut;
+
+public class Application {
+ public static void main(String[] args) {
+ Micronaut.run(Application.class, args);
+ }
+}
diff --git a/test/plugin/scenarios/micronaut-http-scenario/src/main/java/org/apache/skywalking/apm/testcase/micronaut/controller/ErrorHandlerController.java b/test/plugin/scenarios/micronaut-http-scenario/src/main/java/org/apache/skywalking/apm/testcase/micronaut/controller/ErrorHandlerController.java
new file mode 100644
index 000000000..f67aedf6a
--- /dev/null
+++ b/test/plugin/scenarios/micronaut-http-scenario/src/main/java/org/apache/skywalking/apm/testcase/micronaut/controller/ErrorHandlerController.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.testcase.micronaut.controller;
+
+import io.micronaut.http.HttpRequest;
+import io.micronaut.http.HttpResponse;
+import io.micronaut.http.MediaType;
+import io.micronaut.http.annotation.Controller;
+import io.micronaut.http.annotation.Error;
+
+@Controller
+public class ErrorHandlerController {
+
+ @Error(global = true)
+ public HttpResponse error(HttpRequest request, Throwable e) {
+ return HttpResponse.serverError().contentType(MediaType.TEXT_HTML_TYPE)
+ .body("causeError -> ");
+ }
+}
diff --git a/test/plugin/scenarios/micronaut-http-scenario/src/main/java/org/apache/skywalking/apm/testcase/micronaut/controller/HelloController.java b/test/plugin/scenarios/micronaut-http-scenario/src/main/java/org/apache/skywalking/apm/testcase/micronaut/controller/HelloController.java
new file mode 100644
index 000000000..f2f5b139a
--- /dev/null
+++ b/test/plugin/scenarios/micronaut-http-scenario/src/main/java/org/apache/skywalking/apm/testcase/micronaut/controller/HelloController.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.testcase.micronaut.controller;
+
+import io.micronaut.http.HttpRequest;
+import io.micronaut.http.MediaType;
+import io.micronaut.http.annotation.Controller;
+import io.micronaut.http.annotation.Get;
+import io.micronaut.http.client.HttpClient;
+import io.micronaut.http.client.annotation.Client;
+import jakarta.inject.Inject;
+
+@Controller("/micronaut")
+public class HelloController {
+ @Inject
+ @Client("http://localhost:8081")
+ private HttpClient client;
+
+ @Get(value = "healthCheck")
+ public String checkHealth() {
+ return "checked";
+ }
+
+ @Get(produces = MediaType.TEXT_PLAIN, value = "start")
+ public String start() throws InterruptedException {
+ try {
+ client.toBlocking().retrieve(HttpRequest.GET("/micronaut/success?a=1&b=2"));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ try {
+ client.toBlocking().retrieve(HttpRequest.GET("/micronaut/404"));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ try {
+ client.toBlocking().retrieve(HttpRequest.GET("/micronaut/error"));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return "end";
+ }
+
+ @Get(produces = MediaType.TEXT_PLAIN, value = "success")
+ public String success() {
+ return "success";
+ }
+
+ @Get(produces = MediaType.TEXT_PLAIN, value = "error")
+ public String error() {
+ throw new NullPointerException();
+ }
+}
diff --git a/test/plugin/scenarios/micronaut-http-scenario/support-version.list b/test/plugin/scenarios/micronaut-http-scenario/support-version.list
new file mode 100644
index 000000000..fe14e0896
--- /dev/null
+++ b/test/plugin/scenarios/micronaut-http-scenario/support-version.list
@@ -0,0 +1,22 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+
+3.6.0
+3.5.4
+3.4.3
+3.3.4
+3.2.7
+3.2.0
\ No newline at end of file