Skip to content
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

Add support for Nacos Client (#9961) #12849

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/supported-libraries.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ These are the supported libraries and frameworks:
| [Micrometer](https://micrometer.io/) | 1.5+ | [opentelemetry-micrometer-1.5](../instrumentation/micrometer/micrometer-1.5/library) | none |
| [MongoDB Driver](https://mongodb.github.io/mongo-java-driver/) | 3.1+ | [opentelemetry-mongo-3.1](../instrumentation/mongo/mongo-3.1/library) | [Database Client Spans] |
| [MyBatis](https://mybatis.org/mybatis-3/) | 3.2+ | N/A | none |
| [Nacos](https://nacos.io/) | 2.0.3+ | N/A | none |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps use Nacos Client since the instrumentation is for the client

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I will make changes here.

| [Netty HTTP codec [5]](https://github.com/netty/netty) | 3.8+ | [opentelemetry-netty-4.1](../instrumentation/netty/netty-4.1/library) | [HTTP Client Spans], [HTTP Client Metrics], [HTTP Server Spans], [HTTP Server Metrics] |
| [OkHttp](https://github.com/square/okhttp/) | 2.2+ | [opentelemetry-okhttp-3.0](../instrumentation/okhttp/okhttp-3.0/library) | [HTTP Client Spans], [HTTP Client Metrics] |
| [Oracle UCP](https://docs.oracle.com/database/121/JJUCP/) | 11.2+ | [opentelemetry-oracle-ucp-11.2](../instrumentation/oracle-ucp-11.2/library) | [Database Pool Metrics] |
Expand Down
55 changes: 55 additions & 0 deletions instrumentation/nacos-client-2.0.3/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
## Enhancement Methods
- `com.alibaba.nacos.common.remote.client.grpc.GrpcConnection#request`
- `com.alibaba.nacos.common.remote.client.RpcClient#handleServerRequest`

## Span Info Details
<table border="1">
<thead>
<tr>
<th>Request Child Class</th>
<th>SpanName</th>
<th>Additional Tags</th>
</tr>
</thead>
<tbody>
<tr>
<td>InstanceRequest</td>
<td>Nacos/{$(lnstanceRequest.getType()}</td>
<td rowspan="5">nacos.namespace nacos.group nacos.service.name</td>
</tr>
<tr>
<td>ServiceQueryRequest</td>
<td>Nacos/queryService</td>
</tr>
<tr>
<td>SubscribeServiceRequest</td>
<td>Nacos/subscribeService,Nacos/unsubscribeService</td>
</tr>
<tr>
<td>ServicelistRequest</td>
<td>Nacos/getServicelist</td>
</tr>
<tr>
<td>ConfigQueryRequest</td>
<td>Nacos/queryConfig</td>
</tr>
<tr>
<td>ConfigPublishRequest</td>
<td>Nacos/publishConfig</td>
<td rowspan="3">nacos.data.id nacos.group nacos.tenant</td>
</tr>
<tr>
<td>ConfigRemoveRequest</td>
<td>Nacos/removeConfig</td>
</tr>
<tr>
<td>ConfigChangeNotifyRequest</td>
<td>Nacos/notifyConfigChange</td>
</tr>
<tr>
<td>NotifySubscriberRequest</td>
<td>Nacos/notifySubscribeChange</td>
<td>nacos.group nacos.service.name</td>
</tr>
</tbody>
</table>
24 changes: 24 additions & 0 deletions instrumentation/nacos-client-2.0.3/javaagent/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
plugins {
id("otel.javaagent-instrumentation")
}

muzzle {
pass {
group.set("com.alibaba.nacos")
module.set("nacos-client")
versions.set("[2.0.3,)")
skip("0.5.0", "0.6.1", "1.1.2", "1.1.4", "1.4.7", "2.0.1", "2.0.2")
assertInverse.set(true)
}
}

dependencies {
val nacosClientVersion = "2.0.3"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

usually we don't use a separate variable for the instrumented library version, since this is used only in 1 place you could inline it
why are you suing 2.0.3, as far as I can tell tests pass with 2.0.0

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The version 2.0.3 was chosen because I referred to the requirements described in issue #9961. However, after testing, I found that version 2.0.0 also works. I will make changes here.

implementation("com.alibaba.nacos:nacos-client:$nacosClientVersion")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

implementation may not be used here. implementation dependencies are bundled inside the agent jar which is not desired. Usually we use library that is our custom scope that means compileOnly + testImplementation. library also supports running tests with the latest version of the library with -PtestLatestDeps=true (currently tests don't compile with the latest version, you can use latestDepTestLibrary to limit the latest version or you could define tests suites)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I will make changes here.

testImplementation("javax.annotation:javax.annotation-api:1.3.2")
}

tasks.withType<Test>().configureEach {
jvmArgs("--add-opens=java.base/java.lang=ALL-UNNAMED")
jvmArgs("-XX:+IgnoreUnrecognizedVMOptions")
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this really needed?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I will make changes here.

Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.nacos.client.v2_0_3;

import io.opentelemetry.api.common.AttributeKey;

public class NacosClientConstants {
private NacosClientConstants() {}

public static final String NACOS_PREFIX = "Nacos/";

public static final String SERVER_CHECK = "serverCheck";

public static final String QUERY_SERVICE = "queryService";

public static final String SUBSCRIBE_SERVICE = "subscribeService";

public static final String UNSUBSCRIBE_SERVICE = "unsubscribeService";

public static final String QUERY_CONFIG = "queryConfig";

public static final String PUBLISH_CONFIG = "publishConfig";

public static final String REMOVE_CONFIG = "removeConfig";

public static final String GET_SERVICE_LIST = "getServiceList";

public static final String NOTIFY_SUBSCRIBE_CHANGE = "notifySubscribeChange";

public static final String NOTIFY_CONFIG_CHANGE = "notifyConfigChange";

public static final AttributeKey<String> NACOS_NAME_SPACE_ATTR =
AttributeKey.stringKey("nacos.namespace");

public static final AttributeKey<String> NACOS_GROUP_NAME_ATTR =
AttributeKey.stringKey("nacos.group.name");

public static final AttributeKey<String> NACOS_SERVICE_NAME_ATTR =
AttributeKey.stringKey("nacos.service.name");

public static final AttributeKey<String> NACOS_DATA_ID_ATTR =
AttributeKey.stringKey("nacos.data.id");

public static final AttributeKey<String> NACOS_GROUP_ATTR = AttributeKey.stringKey("nacos.group");

public static final AttributeKey<String> NACOS_TENANT_ATTR =
AttributeKey.stringKey("nacos.tenant");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.nacos.client.v2_0_3;

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.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.request.Request;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nonnull;

public class NacosClientHelper {
private static final NacosClientRequestOperator UNKNOWN_OPERATOR =
new NacosClientRequestOperator(request -> request.getClass().getSimpleName(), null);
private static final Map<Class<? extends Request>, NacosClientRequestOperator>
KNOWN_OPERATOR_MAP = new HashMap<>();

private NacosClientHelper() {}

static {
KNOWN_OPERATOR_MAP.put(
InstanceRequest.class,
new NacosClientRequestOperator(
request -> ((InstanceRequest) request).getType(),
(attributesBuilder, request) -> {
InstanceRequest instanceRequest = (InstanceRequest) request;
attributesBuilder.put(
NacosClientConstants.NACOS_NAME_SPACE_ATTR, instanceRequest.getNamespace());
attributesBuilder.put(
NacosClientConstants.NACOS_GROUP_NAME_ATTR, instanceRequest.getGroupName());
attributesBuilder.put(
NacosClientConstants.NACOS_SERVICE_NAME_ATTR, instanceRequest.getServiceName());
}));

KNOWN_OPERATOR_MAP.put(
ServiceQueryRequest.class,
new NacosClientRequestOperator(
request -> NacosClientConstants.QUERY_SERVICE,
(attributesBuilder, request) -> {
ServiceQueryRequest serviceQueryRequest = (ServiceQueryRequest) request;
attributesBuilder.put(
NacosClientConstants.NACOS_NAME_SPACE_ATTR, serviceQueryRequest.getNamespace());
attributesBuilder.put(
NacosClientConstants.NACOS_GROUP_NAME_ATTR, serviceQueryRequest.getGroupName());
attributesBuilder.put(
NacosClientConstants.NACOS_SERVICE_NAME_ATTR,
serviceQueryRequest.getServiceName());
}));

KNOWN_OPERATOR_MAP.put(
SubscribeServiceRequest.class,
new NacosClientRequestOperator(
request ->
((SubscribeServiceRequest) request).isSubscribe()
? NacosClientConstants.SUBSCRIBE_SERVICE
: NacosClientConstants.UNSUBSCRIBE_SERVICE,
(attributesBuilder, request) -> {
SubscribeServiceRequest subscribeServiceRequest = (SubscribeServiceRequest) request;
attributesBuilder.put(
NacosClientConstants.NACOS_NAME_SPACE_ATTR,
subscribeServiceRequest.getNamespace());
attributesBuilder.put(
NacosClientConstants.NACOS_GROUP_NAME_ATTR,
subscribeServiceRequest.getGroupName());
attributesBuilder.put(
NacosClientConstants.NACOS_SERVICE_NAME_ATTR,
subscribeServiceRequest.getServiceName());
}));

KNOWN_OPERATOR_MAP.put(
ServiceListRequest.class,
new NacosClientRequestOperator(
request -> NacosClientConstants.GET_SERVICE_LIST,
(attributesBuilder, request) -> {
ServiceListRequest serviceListRequest = (ServiceListRequest) request;
attributesBuilder.put(
NacosClientConstants.NACOS_NAME_SPACE_ATTR, serviceListRequest.getNamespace());
attributesBuilder.put(
NacosClientConstants.NACOS_GROUP_NAME_ATTR, serviceListRequest.getGroupName());
attributesBuilder.put(
NacosClientConstants.NACOS_SERVICE_NAME_ATTR,
serviceListRequest.getServiceName());
}));

KNOWN_OPERATOR_MAP.put(
ConfigQueryRequest.class,
new NacosClientRequestOperator(
request -> NacosClientConstants.QUERY_CONFIG,
(attributesBuilder, request) -> {
ConfigQueryRequest configQueryRequest = (ConfigQueryRequest) request;
attributesBuilder.put(
NacosClientConstants.NACOS_DATA_ID_ATTR, configQueryRequest.getDataId());
attributesBuilder.put(
NacosClientConstants.NACOS_GROUP_ATTR, configQueryRequest.getGroup());
attributesBuilder.put(
NacosClientConstants.NACOS_TENANT_ATTR, configQueryRequest.getTenant());
}));

KNOWN_OPERATOR_MAP.put(
ConfigPublishRequest.class,
new NacosClientRequestOperator(
request -> NacosClientConstants.PUBLISH_CONFIG,
(attributesBuilder, request) -> {
ConfigPublishRequest configPublishRequest = (ConfigPublishRequest) request;
attributesBuilder.put(
NacosClientConstants.NACOS_DATA_ID_ATTR, configPublishRequest.getDataId());
attributesBuilder.put(
NacosClientConstants.NACOS_GROUP_ATTR, configPublishRequest.getGroup());
attributesBuilder.put(
NacosClientConstants.NACOS_TENANT_ATTR, configPublishRequest.getTenant());
}));

KNOWN_OPERATOR_MAP.put(
ConfigRemoveRequest.class,
new NacosClientRequestOperator(
request -> NacosClientConstants.REMOVE_CONFIG,
(attributesBuilder, request) -> {
ConfigRemoveRequest configRemoveRequest = (ConfigRemoveRequest) request;
attributesBuilder.put(
NacosClientConstants.NACOS_DATA_ID_ATTR, configRemoveRequest.getDataId());
attributesBuilder.put(
NacosClientConstants.NACOS_GROUP_ATTR, configRemoveRequest.getGroup());
attributesBuilder.put(
NacosClientConstants.NACOS_TENANT_ATTR, configRemoveRequest.getTenant());
}));

KNOWN_OPERATOR_MAP.put(
NotifySubscriberRequest.class,
new NacosClientRequestOperator(
request -> NacosClientConstants.NOTIFY_SUBSCRIBE_CHANGE,
(attributesBuilder, request) -> {
NotifySubscriberRequest notifySubscriberRequest = (NotifySubscriberRequest) request;
attributesBuilder.put(
NacosClientConstants.NACOS_NAME_SPACE_ATTR,
notifySubscriberRequest.getNamespace());
attributesBuilder.put(
NacosClientConstants.NACOS_GROUP_NAME_ATTR,
notifySubscriberRequest.getGroupName());
attributesBuilder.put(
NacosClientConstants.NACOS_SERVICE_NAME_ATTR,
notifySubscriberRequest.getServiceName());
}));

KNOWN_OPERATOR_MAP.put(
ConfigChangeNotifyRequest.class,
new NacosClientRequestOperator(
request -> NacosClientConstants.NOTIFY_CONFIG_CHANGE,
(attributesBuilder, request) -> {
ConfigChangeNotifyRequest configChangeNotifyRequest =
(ConfigChangeNotifyRequest) request;
attributesBuilder.put(
NacosClientConstants.NACOS_DATA_ID_ATTR, configChangeNotifyRequest.getDataId());
attributesBuilder.put(
NacosClientConstants.NACOS_GROUP_ATTR, configChangeNotifyRequest.getGroup());
attributesBuilder.put(
NacosClientConstants.NACOS_TENANT_ATTR, configChangeNotifyRequest.getTenant());
}));
}

@Nonnull
public static NacosClientRequestOperator getOperator(@Nonnull Request request) {
NacosClientRequestOperator nacosClientRequestOperator =
KNOWN_OPERATOR_MAP.get(request.getClass());
if (nacosClientRequestOperator != null) {
return nacosClientRequestOperator;
}
return UNKNOWN_OPERATOR;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.nacos.client.v2_0_3;

import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
import io.opentelemetry.javaagent.instrumentation.nacos.client.v2_0_3.instrumentations.GrpcConnectionInstrumentation;
import io.opentelemetry.javaagent.instrumentation.nacos.client.v2_0_3.instrumentations.RpcClientInstrumentation;
import java.util.Arrays;
import java.util.List;

@AutoService(InstrumentationModule.class)
public class NacosClientInstrumentationModule extends InstrumentationModule
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

our convention is to keep instrumentations that don't implement any semantic conventions disabled by default

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I will rewrite the io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule#defaultEnabled method to disable the nacos-client's InstrumentationModule by default.

implements ExperimentalInstrumentationModule {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are you implementing ExperimentalInstrumentationModule?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I will make changes here.

public NacosClientInstrumentationModule() {
super("nacos-client", "nacos-client-2.0.3");
}

@Override
public List<TypeInstrumentation> typeInstrumentations() {
return Arrays.asList(new GrpcConnectionInstrumentation(), new RpcClientInstrumentation());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

usually we static import Arrays.asList

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I will make changes here.

}
}
Loading
Loading