-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Add the Nacos-Client 2.x plugin #18758
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
6226da8
e55feaa
ffa0c0d
b5b0a64
83a03bb
c951ae5
9e01421
2e226f7
23b18df
3ba349d
8e1878e
7a37848
8243d9f
fe9c879
5e34659
3587cab
e3e1b13
7e763c9
4a8ce06
5b3843e
5903e92
b88dc15
2241c20
150df7d
066f56d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| plugins { | ||
| id("otel.javaagent-instrumentation") | ||
| } | ||
|
|
||
| muzzle { | ||
| pass { | ||
| group.set("com.alibaba.nacos") | ||
| module.set("nacos-client") | ||
| versions.set("[2.0.0,3.0.0)") | ||
| assertInverse.set(true) | ||
| } | ||
| } | ||
|
|
||
| dependencies { | ||
| library("com.alibaba.nacos:nacos-client:2.0.0") | ||
| latestDepTestLibrary("com.alibaba.nacos:nacos-client:2.+") // documented limitation | ||
|
|
||
| testImplementation(project(":instrumentation-api")) | ||
| testImplementation(project(":instrumentation-api-incubator")) | ||
|
|
||
| testImplementation("io.opentelemetry:opentelemetry-api") | ||
| testImplementation("io.opentelemetry:opentelemetry-context") | ||
| testImplementation("com.alibaba.nacos:nacos-client:2.0.0") | ||
|
Comment on lines
+18
to
+23
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think these aren't needed |
||
| } | ||
|
|
||
| tasks.withType<Test>().configureEach { | ||
| systemProperty("collectMetadata", otelProps.collectMetadata) | ||
| } | ||
|
|
||
| val testAgentInstrumentation by tasks.registering(Test::class) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you don't need a separate test task for this, could just add |
||
| testClassesDirs = sourceSets.test.get().output.classesDirs | ||
| classpath = sourceSets.test.get().runtimeClasspath | ||
| include("**/NacosClientAgentInstrumentationTest.class") | ||
|
|
||
| jvmArgs("-Dotel.instrumentation.nacos-client.enabled=true") | ||
| } | ||
|
|
||
| tasks { | ||
| test { | ||
| exclude("**/NacosClientAgentInstrumentationTest.class") | ||
| } | ||
|
|
||
| check { | ||
| dependsOn(testAgentInstrumentation) | ||
| } | ||
| } | ||
|
|
||
| afterEvaluate { | ||
| tasks.withType<Test>().configureEach { | ||
| classpath += sourceSets.main.get().output | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| /* | ||
| * Copyright The OpenTelemetry Authors | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| package io.opentelemetry.javaagent.instrumentation.nacosclient.v2_0; | ||
|
|
||
| import io.opentelemetry.context.Context; | ||
| import io.opentelemetry.context.Scope; | ||
|
|
||
| public class ContextAndScope { | ||
| private final Context context; | ||
| private final Scope scope; | ||
|
|
||
| public ContextAndScope(Context context, Scope scope) { | ||
| this.context = context; | ||
| this.scope = scope; | ||
| } | ||
|
|
||
| public Context getContext() { | ||
| return context; | ||
| } | ||
|
|
||
| public void closeScope() { | ||
| scope.close(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| /* | ||
| * Copyright The OpenTelemetry Authors | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| package io.opentelemetry.javaagent.instrumentation.nacosclient.v2_0; | ||
|
|
||
| import static net.bytebuddy.matcher.ElementMatchers.isMethod; | ||
| import static net.bytebuddy.matcher.ElementMatchers.named; | ||
| import static net.bytebuddy.matcher.ElementMatchers.takesArgument; | ||
| import static net.bytebuddy.matcher.ElementMatchers.takesArguments; | ||
|
|
||
| import com.alibaba.nacos.api.remote.response.Response; | ||
| import com.alibaba.nacos.common.remote.client.RpcClient; | ||
| import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; | ||
| import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; | ||
| import javax.annotation.Nullable; | ||
| import net.bytebuddy.asm.Advice; | ||
| import net.bytebuddy.description.type.TypeDescription; | ||
| import net.bytebuddy.matcher.ElementMatcher; | ||
|
|
||
| class GrpcClientInstrumentation implements TypeInstrumentation { | ||
|
|
||
| @Override | ||
| public ElementMatcher<TypeDescription> typeMatcher() { | ||
| return named("com.alibaba.nacos.common.remote.client.grpc.GrpcClient"); | ||
| } | ||
|
|
||
| @Override | ||
| public void transform(TypeTransformer transformer) { | ||
| transformer.applyAdviceToMethod( | ||
| isMethod() | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| .and(named("serverCheck")) | ||
| .and(takesArguments(3)) | ||
| .and(takesArgument(0, String.class)) | ||
| .and(takesArgument(1, int.class)) | ||
| .and( | ||
| takesArgument( | ||
| 2, named("com.alibaba.nacos.api.grpc.auto.RequestGrpc$RequestFutureStub"))), | ||
| getClass().getName() + "$ServerCheckAdvice"); | ||
| } | ||
|
|
||
| @SuppressWarnings("unused") | ||
| public static class ServerCheckAdvice { | ||
| @Nullable | ||
| @Advice.OnMethodEnter(suppress = Throwable.class, inline = false) | ||
| public static ContextAndScope onEnter( | ||
| @Advice.This RpcClient rpcClient, | ||
| @Advice.Argument(0) String serverIp, | ||
| @Advice.Argument(1) int serverPort) { | ||
| RpcClientServerInfoAccessor.set(rpcClient, new RpcClient.ServerInfo(serverIp, serverPort)); | ||
| return NacosClientSingletons.startClientSpan( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This somewhat deviates from wheat we usually do. Many instrumentations use a class named |
||
| NacosRequestMapper.createServerCheckRequest(serverIp, serverPort)); | ||
| } | ||
|
|
||
| @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class, inline = false) | ||
| public static void onExit( | ||
| @Advice.Argument(0) String serverIp, | ||
| @Advice.Argument(1) int serverPort, | ||
| @Advice.Enter @Nullable ContextAndScope contextAndScope, | ||
| @Advice.Return @Nullable Response response, | ||
| @Advice.Thrown @Nullable Throwable throwable) { | ||
| NacosClientSingletons.endClientSpan( | ||
| contextAndScope, | ||
| NacosRequestMapper.createServerCheckRequest(serverIp, serverPort), | ||
| response, | ||
| throwable); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| /* | ||
| * Copyright The OpenTelemetry Authors | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| package io.opentelemetry.javaagent.instrumentation.nacosclient.v2_0; | ||
|
|
||
| import static net.bytebuddy.matcher.ElementMatchers.isMethod; | ||
| import static net.bytebuddy.matcher.ElementMatchers.named; | ||
| import static net.bytebuddy.matcher.ElementMatchers.takesArgument; | ||
| import static net.bytebuddy.matcher.ElementMatchers.takesArguments; | ||
|
|
||
| import com.alibaba.nacos.api.remote.request.Request; | ||
| import com.alibaba.nacos.api.remote.response.Response; | ||
| import com.alibaba.nacos.common.remote.client.grpc.GrpcConnection; | ||
| import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; | ||
| import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; | ||
| import javax.annotation.Nullable; | ||
| import net.bytebuddy.asm.Advice; | ||
| import net.bytebuddy.description.type.TypeDescription; | ||
| import net.bytebuddy.matcher.ElementMatcher; | ||
|
|
||
| class GrpcConnectionInstrumentation implements TypeInstrumentation { | ||
|
|
||
| @Override | ||
| public ElementMatcher<TypeDescription> typeMatcher() { | ||
| return named("com.alibaba.nacos.common.remote.client.grpc.GrpcConnection"); | ||
| } | ||
|
|
||
| @Override | ||
| public void transform(TypeTransformer transformer) { | ||
| transformer.applyAdviceToMethod( | ||
| isMethod() | ||
| .and(named("request")) | ||
| .and(takesArguments(2)) | ||
| .and(takesArgument(0, named("com.alibaba.nacos.api.remote.request.Request"))) | ||
| .and(takesArgument(1, long.class)), | ||
| getClass().getName() + "$RequestAdvice"); | ||
| } | ||
|
|
||
| @SuppressWarnings("unused") | ||
| public static class RequestAdvice { | ||
|
|
||
| @Nullable | ||
| @Advice.OnMethodEnter(suppress = Throwable.class, inline = false) | ||
| public static State onEnter( | ||
| @Advice.This GrpcConnection connection, @Advice.Argument(0) Request request) { | ||
| NacosClientRequest nacosRequest = | ||
| NacosRequestMapper.mapClientRequest(request, connection.getChannel().authority()); | ||
| if (nacosRequest == null) { | ||
| return null; | ||
| } | ||
| ContextAndScope contextAndScope = NacosClientSingletons.startClientSpan(nacosRequest); | ||
| return contextAndScope == null ? null : new State(nacosRequest, contextAndScope); | ||
| } | ||
|
|
||
| @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class, inline = false) | ||
| public static void onExit( | ||
| @Advice.Enter @Nullable State state, | ||
| @Advice.Return @Nullable Response response, | ||
| @Advice.Thrown @Nullable Throwable throwable) { | ||
| if (state == null) { | ||
| return; | ||
| } | ||
| NacosClientSingletons.endClientSpan( | ||
| state.contextAndScope(), state.request(), response, throwable); | ||
| } | ||
| } | ||
|
|
||
| public static class State { | ||
| private final NacosClientRequest request; | ||
| private final ContextAndScope contextAndScope; | ||
|
|
||
| public State(NacosClientRequest request, ContextAndScope contextAndScope) { | ||
| this.request = request; | ||
| this.contextAndScope = contextAndScope; | ||
| } | ||
|
|
||
| public NacosClientRequest request() { | ||
| return request; | ||
| } | ||
|
|
||
| public ContextAndScope contextAndScope() { | ||
| return contextAndScope; | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| /* | ||
| * Copyright The OpenTelemetry Authors | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| package io.opentelemetry.javaagent.instrumentation.nacosclient.v2_0; | ||
|
|
||
| import com.alibaba.nacos.api.config.remote.request.ConfigChangeNotifyRequest; | ||
| import com.alibaba.nacos.api.config.remote.request.ConfigPublishRequest; | ||
| import com.alibaba.nacos.api.config.remote.request.ConfigQueryRequest; | ||
| import com.alibaba.nacos.api.config.remote.request.ConfigRemoveRequest; | ||
| import com.alibaba.nacos.api.naming.pojo.ServiceInfo; | ||
| import com.alibaba.nacos.api.naming.remote.request.InstanceRequest; | ||
| import com.alibaba.nacos.api.naming.remote.request.NotifySubscriberRequest; | ||
| import com.alibaba.nacos.api.naming.remote.request.ServiceListRequest; | ||
| import com.alibaba.nacos.api.naming.remote.request.ServiceQueryRequest; | ||
| import com.alibaba.nacos.api.naming.remote.request.SubscribeServiceRequest; | ||
| import com.alibaba.nacos.api.remote.response.Response; | ||
| import io.opentelemetry.api.common.AttributeKey; | ||
| import io.opentelemetry.api.common.AttributesBuilder; | ||
| import io.opentelemetry.context.Context; | ||
| import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; | ||
| import javax.annotation.Nullable; | ||
|
|
||
| class NacosClientAttributesExtractor implements AttributesExtractor<NacosClientRequest, Response> { | ||
|
|
||
| private static final AttributeKey<String> NACOS_CATEGORY = | ||
| AttributeKey.stringKey("nacos.category"); | ||
| private static final AttributeKey<String> NACOS_REQUEST_TYPE = | ||
| AttributeKey.stringKey("nacos.request.type"); | ||
| private static final AttributeKey<String> NACOS_NAMESPACE = | ||
| AttributeKey.stringKey("nacos.namespace"); | ||
| private static final AttributeKey<String> NACOS_GROUP = AttributeKey.stringKey("nacos.group"); | ||
| private static final AttributeKey<String> NACOS_SERVICE_NAME = | ||
| AttributeKey.stringKey("nacos.service.name"); | ||
| private static final AttributeKey<String> NACOS_DATA_ID = AttributeKey.stringKey("nacos.data.id"); | ||
| private static final AttributeKey<String> NACOS_TENANT = AttributeKey.stringKey("nacos.tenant"); | ||
|
|
||
| @Override | ||
| public void onStart( | ||
| AttributesBuilder attributes, Context parentContext, NacosClientRequest request) { | ||
| attributes.put(NACOS_CATEGORY, request.category()); | ||
| attributes.put(NACOS_REQUEST_TYPE, request.request().getClass().getSimpleName()); | ||
|
|
||
| Object rawRequest = request.request(); | ||
| if (rawRequest instanceof InstanceRequest) { | ||
| InstanceRequest instanceRequest = (InstanceRequest) rawRequest; | ||
| put(attributes, NACOS_NAMESPACE, instanceRequest.getNamespace()); | ||
| put(attributes, NACOS_GROUP, instanceRequest.getGroupName()); | ||
| put(attributes, NACOS_SERVICE_NAME, instanceRequest.getServiceName()); | ||
| } else if (rawRequest instanceof ServiceQueryRequest) { | ||
| ServiceQueryRequest serviceQueryRequest = (ServiceQueryRequest) rawRequest; | ||
| put(attributes, NACOS_NAMESPACE, serviceQueryRequest.getNamespace()); | ||
| put(attributes, NACOS_GROUP, serviceQueryRequest.getGroupName()); | ||
| put(attributes, NACOS_SERVICE_NAME, serviceQueryRequest.getServiceName()); | ||
| } else if (rawRequest instanceof SubscribeServiceRequest) { | ||
| SubscribeServiceRequest subscribeServiceRequest = (SubscribeServiceRequest) rawRequest; | ||
| put(attributes, NACOS_NAMESPACE, subscribeServiceRequest.getNamespace()); | ||
| put(attributes, NACOS_GROUP, subscribeServiceRequest.getGroupName()); | ||
| put(attributes, NACOS_SERVICE_NAME, subscribeServiceRequest.getServiceName()); | ||
| } else if (rawRequest instanceof ServiceListRequest) { | ||
| ServiceListRequest serviceListRequest = (ServiceListRequest) rawRequest; | ||
| put(attributes, NACOS_NAMESPACE, serviceListRequest.getNamespace()); | ||
| put(attributes, NACOS_GROUP, serviceListRequest.getGroupName()); | ||
| put(attributes, NACOS_SERVICE_NAME, serviceListRequest.getServiceName()); | ||
|
Comment on lines
+46
to
+65
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. all of these are subclasses of |
||
| } else if (rawRequest instanceof ConfigQueryRequest) { | ||
| ConfigQueryRequest configQueryRequest = (ConfigQueryRequest) rawRequest; | ||
| put(attributes, NACOS_DATA_ID, configQueryRequest.getDataId()); | ||
| put(attributes, NACOS_GROUP, configQueryRequest.getGroup()); | ||
| put(attributes, NACOS_TENANT, configQueryRequest.getTenant()); | ||
| } else if (rawRequest instanceof ConfigPublishRequest) { | ||
| ConfigPublishRequest configPublishRequest = (ConfigPublishRequest) rawRequest; | ||
| put(attributes, NACOS_DATA_ID, configPublishRequest.getDataId()); | ||
| put(attributes, NACOS_GROUP, configPublishRequest.getGroup()); | ||
| put(attributes, NACOS_TENANT, configPublishRequest.getTenant()); | ||
| } else if (rawRequest instanceof ConfigRemoveRequest) { | ||
| ConfigRemoveRequest configRemoveRequest = (ConfigRemoveRequest) rawRequest; | ||
| put(attributes, NACOS_DATA_ID, configRemoveRequest.getDataId()); | ||
| put(attributes, NACOS_GROUP, configRemoveRequest.getGroup()); | ||
| put(attributes, NACOS_TENANT, configRemoveRequest.getTenant()); | ||
| } else if (rawRequest instanceof NotifySubscriberRequest) { | ||
| ServiceInfo serviceInfo = ((NotifySubscriberRequest) rawRequest).getServiceInfo(); | ||
| if (serviceInfo != null) { | ||
| put(attributes, NACOS_GROUP, serviceInfo.getGroupName()); | ||
| put(attributes, NACOS_SERVICE_NAME, serviceInfo.getName()); | ||
| } | ||
| } else if (rawRequest instanceof ConfigChangeNotifyRequest) { | ||
| ConfigChangeNotifyRequest configChangeNotifyRequest = (ConfigChangeNotifyRequest) rawRequest; | ||
| put(attributes, NACOS_DATA_ID, configChangeNotifyRequest.getDataId()); | ||
| put(attributes, NACOS_GROUP, configChangeNotifyRequest.getGroup()); | ||
| put(attributes, NACOS_TENANT, configChangeNotifyRequest.getTenant()); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public void onEnd( | ||
| AttributesBuilder attributes, | ||
| Context context, | ||
| NacosClientRequest request, | ||
| @Nullable Response response, | ||
| @Nullable Throwable error) {} | ||
|
|
||
| private static void put( | ||
| AttributesBuilder attributes, AttributeKey<String> key, @Nullable String value) { | ||
| if (value != null && !value.isEmpty()) { | ||
| attributes.put(key, value); | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
did you manually edit this? should the latest version be
3.2.1?