From c5c6ba4ee6ffacc4b39220708415b6c37a23620a Mon Sep 17 00:00:00 2001 From: FAWC438 Date: Tue, 19 Dec 2023 19:41:02 +0800 Subject: [PATCH 1/5] Migrate ClientWorker and ConfigRpcTransportClient from dynamic proxy to delegate class --- .../client/config/NacosConfigService.java | 11 +- .../client/config/impl/ClientWorker.java | 32 +- .../proxy/ClientWorkerProxy.java} | 27 +- .../proxy/ConfigRpcTransportClientProxy.java} | 33 +- .../client/monitor/TraceDynamicProxy.java | 202 +------- .../config/ClientWorkerTraceDelegate.java | 474 ++++++++++++++++++ ...gRpcTransportClientProxyTraceDelegate.java | 363 ++++++++++++++ .../client/monitor/TraceDynamicProxyTest.java | 10 +- 8 files changed, 895 insertions(+), 257 deletions(-) rename client/src/main/java/com/alibaba/nacos/client/{monitor/config/ClientWorkerTraceProxy.java => config/proxy/ClientWorkerProxy.java} (83%) rename client/src/main/java/com/alibaba/nacos/client/{monitor/config/ConfigRpcTransportClientTraceProxy.java => config/proxy/ConfigRpcTransportClientProxy.java} (79%) create mode 100644 client/src/main/java/com/alibaba/nacos/client/monitor/config/ClientWorkerTraceDelegate.java create mode 100644 client/src/main/java/com/alibaba/nacos/client/monitor/config/ConfigRpcTransportClientProxyTraceDelegate.java diff --git a/client/src/main/java/com/alibaba/nacos/client/config/NacosConfigService.java b/client/src/main/java/com/alibaba/nacos/client/config/NacosConfigService.java index e451972d3bd..f94549127ce 100644 --- a/client/src/main/java/com/alibaba/nacos/client/config/NacosConfigService.java +++ b/client/src/main/java/com/alibaba/nacos/client/config/NacosConfigService.java @@ -36,12 +36,12 @@ import com.alibaba.nacos.client.config.utils.ParamUtils; import com.alibaba.nacos.client.env.NacosClientProperties; import com.alibaba.nacos.client.monitor.TraceDynamicProxy; -import com.alibaba.nacos.client.monitor.config.ClientWorkerTraceProxy; -import com.alibaba.nacos.common.constant.NacosSemanticAttributes; +import com.alibaba.nacos.client.monitor.config.ClientWorkerTraceDelegate; import com.alibaba.nacos.client.monitor.config.ConfigTrace; import com.alibaba.nacos.client.utils.LogUtils; import com.alibaba.nacos.client.utils.ParamUtil; import com.alibaba.nacos.client.utils.ValidatorUtils; +import com.alibaba.nacos.common.constant.NacosSemanticAttributes; import com.alibaba.nacos.common.utils.StringUtils; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanBuilder; @@ -76,7 +76,7 @@ public class NacosConfigService implements ConfigService { /** * long polling. */ - private final ClientWorkerTraceProxy worker; + private final ClientWorker worker; private String namespace; @@ -91,8 +91,7 @@ public NacosConfigService(Properties properties) throws NacosException { ServerListManager serverListManager = new ServerListManager(clientProperties); serverListManager.start(); - this.worker = TraceDynamicProxy.getClientWorkerTraceProxy( - new ClientWorker(this.configFilterChainManager, serverListManager, clientProperties)); + this.worker = new ClientWorkerTraceDelegate(this.configFilterChainManager, serverListManager, clientProperties); // will be deleted in 2.0 later versions agent = TraceDynamicProxy.getHttpAgentTraceProxy(new ServerHttpAgent(serverListManager)); @@ -224,7 +223,7 @@ private String getConfigInner(String tenant, String dataId, String group, long t cr.setContent(content); String encryptedDataKey = getSnapshotWithTrace(agent.getName(), dataId, group, tenant, true); - + cr.setEncryptedDataKey(encryptedDataKey); configFilterChainManager.doFilter(null, cr); content = cr.getContent(); diff --git a/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java b/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java index eb82a7cab10..e6c3d5a3e51 100644 --- a/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java +++ b/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java @@ -43,16 +43,16 @@ import com.alibaba.nacos.client.config.utils.ContentUtils; import com.alibaba.nacos.client.env.NacosClientProperties; import com.alibaba.nacos.client.monitor.TraceDynamicProxy; -import com.alibaba.nacos.client.monitor.config.ClientWorkerTraceProxy; +import com.alibaba.nacos.client.config.proxy.ClientWorkerProxy; import com.alibaba.nacos.client.monitor.config.ConfigMetrics; -import com.alibaba.nacos.client.monitor.config.ConfigRpcTransportClientTraceProxy; +import com.alibaba.nacos.client.config.proxy.ConfigRpcTransportClientProxy; +import com.alibaba.nacos.client.monitor.config.ConfigRpcTransportClientProxyTraceDelegate; import com.alibaba.nacos.client.naming.utils.CollectionUtils; import com.alibaba.nacos.client.utils.AppNameUtils; import com.alibaba.nacos.client.utils.EnvUtil; import com.alibaba.nacos.client.utils.LogUtils; import com.alibaba.nacos.client.utils.ParamUtil; import com.alibaba.nacos.client.utils.TenantUtil; -import com.alibaba.nacos.common.lifecycle.Closeable; import com.alibaba.nacos.common.notify.Event; import com.alibaba.nacos.common.notify.NotifyCenter; import com.alibaba.nacos.common.notify.listener.Subscriber; @@ -103,7 +103,7 @@ * * @author Nacos */ -public class ClientWorker implements Closeable, ClientWorkerTraceProxy { +public class ClientWorker implements ClientWorkerProxy { private static final Logger LOGGER = LogUtils.logger(ClientWorker.class); @@ -130,7 +130,7 @@ public class ClientWorker implements Closeable, ClientWorkerTraceProxy { private long timeout; - private final ConfigRpcTransportClientTraceProxy agent; + protected final ConfigRpcTransportClientProxy agent; private int taskPenaltyTime; @@ -154,8 +154,8 @@ public class ClientWorker implements Closeable, ClientWorkerTraceProxy { */ public void addListeners(String dataId, String group, List listeners) throws NacosException { group = blank2defaultGroup(group); - - CacheData cache = TraceDynamicProxy.getClientWorkerTraceProxy(this).addCacheDataIfAbsent(dataId, group); + + CacheData cache = addCacheDataIfAbsent(dataId, group); synchronized (cache) { @@ -182,8 +182,8 @@ public void addTenantListeners(String dataId, String group, List multiTaskExecutor = new HashMap<>(); @@ -1114,7 +1114,7 @@ public ConfigResponse queryConfig(String dataId, String group, String tenant, lo rpcClient = ensureRpcClient(String.valueOf(cacheData.getTaskId())); } } - + ConfigQueryResponse response = (ConfigQueryResponse) agent.requestProxy(rpcClient, request, readTimeouts); ConfigResponse configResponse = new ConfigResponse(); @@ -1158,7 +1158,7 @@ public ConfigResponse queryConfig(String dataId, String group, String tenant, lo } private Response requestProxy(RpcClient rpcClientInner, Request request) throws NacosException { - return agent.requestProxy(rpcClientInner, request, 3000L); + return requestProxy(rpcClientInner, request, 3000L); } /** @@ -1189,7 +1189,7 @@ public Response requestProxy(RpcClient rpcClientInner, Request request, long tim long start = System.currentTimeMillis(); Response rpcResponse = rpcClientInner.request(request, timeoutMills); - + long cost = System.currentTimeMillis() - start; // Metrics ConfigMetrics.recordRpcCostDurationTimer(rpcClientInner.getConnectionType().getType(), diff --git a/client/src/main/java/com/alibaba/nacos/client/monitor/config/ClientWorkerTraceProxy.java b/client/src/main/java/com/alibaba/nacos/client/config/proxy/ClientWorkerProxy.java similarity index 83% rename from client/src/main/java/com/alibaba/nacos/client/monitor/config/ClientWorkerTraceProxy.java rename to client/src/main/java/com/alibaba/nacos/client/config/proxy/ClientWorkerProxy.java index e22d929fac9..cb5f6e397e7 100644 --- a/client/src/main/java/com/alibaba/nacos/client/monitor/config/ClientWorkerTraceProxy.java +++ b/client/src/main/java/com/alibaba/nacos/client/config/proxy/ClientWorkerProxy.java @@ -16,7 +16,7 @@ * */ -package com.alibaba.nacos.client.monitor.config; +package com.alibaba.nacos.client.config.proxy; import com.alibaba.nacos.api.config.listener.Listener; import com.alibaba.nacos.api.exception.NacosException; @@ -27,17 +27,14 @@ import java.util.List; /** - * {@link com.alibaba.nacos.client.config.impl.ClientWorker} interface for dynamic proxy to trace the ClientWorker by - * OpenTelemetry. + * proxy interface for ClientWorker. * * @author FAWC438 */ -public interface ClientWorkerTraceProxy extends Closeable { - - // Methods for Service level config span +public interface ClientWorkerProxy extends Closeable { /** - * Add listener to config. For trace dynamic proxy. + * Add listener to config. * * @param dataId dataId * @param group group @@ -50,7 +47,7 @@ void addTenantListenersWithContent(String dataId, String group, String content, List listeners) throws NacosException; /** - * Add listener to config. For trace dynamic proxy. + * Add listener to config. * * @param dataId dataId * @param group group @@ -60,7 +57,7 @@ void addTenantListenersWithContent(String dataId, String group, String content, void addTenantListeners(String dataId, String group, List listeners) throws NacosException; /** - * Remove listener from config. For trace dynamic proxy. + * Remove listener from config. * * @param dataId dataId * @param group group @@ -69,7 +66,7 @@ void addTenantListenersWithContent(String dataId, String group, String content, void removeTenantListener(String dataId, String group, Listener listener); /** - * Remove all listeners from config. For trace dynamic proxy. + * Remove all listeners from config. * * @param dataId dataId * @param group group @@ -83,7 +80,7 @@ ConfigResponse getServerConfig(String dataId, String group, String tenant, long throws NacosException; /** - * Remove all listeners from config. For trace dynamic proxy. + * Remove all listeners from config. * * @param dataId dataId * @param group group @@ -95,7 +92,7 @@ ConfigResponse getServerConfig(String dataId, String group, String tenant, long boolean removeConfig(String dataId, String group, String tenant, String tag) throws NacosException; /** - * Remove all listeners from config. For trace dynamic proxy. + * Remove all listeners from config. * * @param dataId dataId * @param group group @@ -135,7 +132,7 @@ boolean publishConfig(String dataId, String group, String tenant, String appName CacheData addCacheDataIfAbsent(String dataId, String group, String tenant) throws NacosException; /** - * Check whether the server is health. For trace dynamic proxy. + * Check whether the server is health. * * @return boolean */ @@ -144,14 +141,14 @@ boolean publishConfig(String dataId, String group, String tenant, String appName // Other necessary methods /** - * Get agent tenant. For trace dynamic proxy. + * Get agent tenant. * * @return tenant */ String getAgentTenant(); /** - * Get agent name. For trace dynamic proxy. + * Get agent name. * * @return name */ diff --git a/client/src/main/java/com/alibaba/nacos/client/monitor/config/ConfigRpcTransportClientTraceProxy.java b/client/src/main/java/com/alibaba/nacos/client/config/proxy/ConfigRpcTransportClientProxy.java similarity index 79% rename from client/src/main/java/com/alibaba/nacos/client/monitor/config/ConfigRpcTransportClientTraceProxy.java rename to client/src/main/java/com/alibaba/nacos/client/config/proxy/ConfigRpcTransportClientProxy.java index 6e976d7d3a3..f6f9145d56d 100644 --- a/client/src/main/java/com/alibaba/nacos/client/monitor/config/ConfigRpcTransportClientTraceProxy.java +++ b/client/src/main/java/com/alibaba/nacos/client/config/proxy/ConfigRpcTransportClientProxy.java @@ -16,7 +16,7 @@ * */ -package com.alibaba.nacos.client.monitor.config; +package com.alibaba.nacos.client.config.proxy; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.remote.request.Request; @@ -29,17 +29,14 @@ import java.util.concurrent.ScheduledExecutorService; /** - * {@link com.alibaba.nacos.client.config.impl.ClientWorker.ConfigRpcTransportClient} interface for dynamic proxy to - * trace the ClientWorker.ConfigRpcTransportClient by OpenTelemetry. + * proxy interface for {@link com.alibaba.nacos.client.config.impl.ClientWorker.ConfigRpcTransportClient}. * * @author FAWC438 */ -public interface ConfigRpcTransportClientTraceProxy extends Closeable { - - // Methods for Worker level config span +public interface ConfigRpcTransportClientProxy extends Closeable { /** - * Query config from server. For trace dynamic proxy. + * Query config from server. * * @param dataId dataId * @param group group @@ -53,7 +50,7 @@ ConfigResponse queryConfig(String dataId, String group, String tenant, long read throws NacosException; /** - * Publish config to server. For trace dynamic proxy. + * Publish config to server. * * @param dataId dataId * @param group group @@ -72,7 +69,7 @@ boolean publishConfig(String dataId, String group, String tenant, String appName String content, String encryptedDataKey, String casMd5, String type) throws NacosException; /** - * Remove config from server. For trace dynamic proxy. + * Remove config from server. * * @param dataId dataId * @param group group @@ -86,7 +83,7 @@ boolean publishConfig(String dataId, String group, String tenant, String appName // Methods for Rpc level config span /** - * Request proxy. For trace dynamic proxy. + * Request proxy. * * @param rpcClientInner rpcClientInner * @param request request @@ -99,19 +96,19 @@ boolean publishConfig(String dataId, String group, String tenant, String appName // Other necessary methods /** - * Notify listen config. For trace dynamic proxy. + * Notify listen config. */ void notifyListenConfig(); /** - * Get tenant. For trace dynamic proxy. + * Get tenant. * * @return tenant */ String getTenant(); /** - * Remove cache. For trace dynamic proxy. + * Remove cache. * * @param dataId dataId * @param group group @@ -119,35 +116,35 @@ boolean publishConfig(String dataId, String group, String tenant, String appName void removeCache(String dataId, String group); /** - * Get agent name. For trace dynamic proxy. + * Get agent name. * * @return agent name */ String getName(); /** - * Get server list manager. For trace dynamic proxy. + * Get server list manager. * * @return server list manager */ ServerListManager getServerListManager(); /** - * Set executor. For trace dynamic proxy. + * Set executor. * * @param executor executor */ void setExecutor(ScheduledExecutorService executor); /** - * Start agent. For trace dynamic proxy. + * Start agent. * * @throws NacosException NacosException */ void start() throws NacosException; /** - * Check whether the server is health. For trace dynamic proxy. + * Check whether the server is health. * * @return boolean */ diff --git a/client/src/main/java/com/alibaba/nacos/client/monitor/TraceDynamicProxy.java b/client/src/main/java/com/alibaba/nacos/client/monitor/TraceDynamicProxy.java index 2d03fc4c098..35c15fc29ff 100644 --- a/client/src/main/java/com/alibaba/nacos/client/monitor/TraceDynamicProxy.java +++ b/client/src/main/java/com/alibaba/nacos/client/monitor/TraceDynamicProxy.java @@ -26,13 +26,11 @@ import com.alibaba.nacos.api.naming.remote.response.QueryServiceResponse; import com.alibaba.nacos.api.naming.remote.response.ServiceListResponse; import com.alibaba.nacos.api.remote.request.Request; -import com.alibaba.nacos.api.remote.response.Response; import com.alibaba.nacos.client.config.filter.impl.ConfigResponse; import com.alibaba.nacos.client.config.http.HttpAgent; import com.alibaba.nacos.client.config.impl.CacheData; import com.alibaba.nacos.client.config.impl.ClientWorker; -import com.alibaba.nacos.client.monitor.config.ClientWorkerTraceProxy; -import com.alibaba.nacos.client.monitor.config.ConfigRpcTransportClientTraceProxy; +import com.alibaba.nacos.client.config.proxy.ClientWorkerProxy; import com.alibaba.nacos.client.monitor.config.ConfigTrace; import com.alibaba.nacos.client.monitor.naming.NamingGrpcRedoServiceTraceProxy; import com.alibaba.nacos.client.monitor.naming.NamingTrace; @@ -43,7 +41,6 @@ import com.alibaba.nacos.client.naming.remote.http.NamingHttpClientProxy; import com.alibaba.nacos.common.constant.NacosSemanticAttributes; import com.alibaba.nacos.common.http.HttpRestResult; -import com.alibaba.nacos.common.remote.client.RpcClient; import com.alibaba.nacos.common.remote.client.ServerRequestHandler; import com.alibaba.nacos.common.utils.HttpMethod; import com.alibaba.nacos.common.utils.StringUtils; @@ -52,7 +49,6 @@ import io.opentelemetry.api.trace.SpanBuilder; import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.api.trace.StatusCode; -import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; @@ -70,9 +66,10 @@ public class TraceDynamicProxy { // Config module - public static ClientWorkerTraceProxy getClientWorkerTraceProxy(ClientWorker clientWorker) { - return (ClientWorkerTraceProxy) Proxy.newProxyInstance(TraceDynamicProxy.class.getClassLoader(), - new Class[] {ClientWorkerTraceProxy.class}, (proxy, method, args) -> { + // TODO: Remove this method + public static ClientWorkerProxy getClientWorkerTraceProxy(ClientWorker clientWorker) { + return (ClientWorkerProxy) Proxy.newProxyInstance(TraceDynamicProxy.class.getClassLoader(), + new Class[] {ClientWorkerProxy.class}, (proxy, method, args) -> { String methodName = method.getName(); SpanBuilder spanBuilder = ConfigTrace.getClientConfigServiceSpanBuilder(methodName); @@ -310,195 +307,6 @@ public static ClientWorkerTraceProxy getClientWorkerTraceProxy(ClientWorker clie }); } - public static ConfigRpcTransportClientTraceProxy getConfigRpcTransportClientTraceProxy( - ClientWorker.ConfigRpcTransportClient configRpcTransportClient) { - return (ConfigRpcTransportClientTraceProxy) Proxy.newProxyInstance(TraceDynamicProxy.class.getClassLoader(), - new Class[] {ConfigRpcTransportClientTraceProxy.class}, (proxy, method, args) -> { - String methodName = method.getName(); - - SpanBuilder spanBuilder = ConfigTrace.getClientConfigWorkerSpanBuilder(methodName); - spanBuilder.setAttribute(SemanticAttributes.CODE_NAMESPACE, - configRpcTransportClient.getClass().getName()); - spanBuilder.setAttribute(SemanticAttributes.CODE_FUNCTION, methodName); - spanBuilder.setAttribute(NacosSemanticAttributes.AGENT_NAME, configRpcTransportClient.getName()); - - switch (methodName) { - case "queryConfig": { - Object result; - Span span = spanBuilder.startSpan(); - try (Scope ignored = span.makeCurrent()) { - - if (span.isRecording()) { - span.setAttribute(NacosSemanticAttributes.DATA_ID, (String) args[0]); - span.setAttribute(NacosSemanticAttributes.GROUP, (String) args[1]); - span.setAttribute(NacosSemanticAttributes.TENANT, (String) args[2]); - span.setAttribute(NacosSemanticAttributes.TIMEOUT_MS, (long) args[3]); - span.setAttribute(NacosSemanticAttributes.NOTIFY, (boolean) args[4]); - } - - result = method.invoke(configRpcTransportClient, args); - - if (span.isRecording() && result != null) { - ConfigResponse configResponse = (ConfigResponse) result; - if (configResponse.getConfigType() == null) { - span.setStatus(StatusCode.ERROR, "Config not found"); - } else { - span.setStatus(StatusCode.OK, "Query Config success"); - } - } - - } catch (InvocationTargetException e) { - Throwable targetException = e.getTargetException(); - span.recordException(targetException); - span.setStatus(StatusCode.ERROR, targetException.getClass().getSimpleName()); - throw targetException; - } finally { - span.end(); - } - - return result; - } - case "publishConfig": { - Object result; - Span span = spanBuilder.startSpan(); - try (Scope ignored = span.makeCurrent()) { - - if (span.isRecording()) { - span.setAttribute(NacosSemanticAttributes.DATA_ID, (String) args[0]); - span.setAttribute(NacosSemanticAttributes.GROUP, (String) args[1]); - span.setAttribute(NacosSemanticAttributes.TENANT, (String) args[2]); - span.setAttribute(NacosSemanticAttributes.APPLICATION_NAME, (String) args[3]); - span.setAttribute(NacosSemanticAttributes.TAG, (String) args[4]); - span.setAttribute(NacosSemanticAttributes.CONTENT, (String) args[6]); - span.setAttribute(NacosSemanticAttributes.CONFIG_TYPE, (String) args[9]); - } - - result = method.invoke(configRpcTransportClient, args); - - if (span.isRecording() && result != null) { - boolean publishResult = (boolean) result; - if (publishResult) { - span.setStatus(StatusCode.OK, "Publish config success"); - } else { - span.setStatus(StatusCode.ERROR, "Publish config failed"); - } - } - - } catch (InvocationTargetException e) { - Throwable targetException = e.getTargetException(); - span.recordException(targetException); - span.setStatus(StatusCode.ERROR, targetException.getClass().getSimpleName()); - throw targetException; - } finally { - span.end(); - } - - return result; - } - case "removeConfig": { - Object result; - Span span = spanBuilder.startSpan(); - try (Scope ignored = span.makeCurrent()) { - - if (span.isRecording()) { - span.setAttribute(NacosSemanticAttributes.DATA_ID, (String) args[0]); - span.setAttribute(NacosSemanticAttributes.GROUP, (String) args[1]); - span.setAttribute(NacosSemanticAttributes.TENANT, (String) args[2]); - span.setAttribute(NacosSemanticAttributes.TAG, (String) args[3]); - } - - result = method.invoke(configRpcTransportClient, args); - - if (span.isRecording() && result != null) { - boolean removeResult = (boolean) result; - if (removeResult) { - span.setStatus(StatusCode.OK, "Remove config success"); - } else { - span.setStatus(StatusCode.ERROR, "Remove config failed"); - } - } - - } catch (InvocationTargetException e) { - Throwable targetException = e.getTargetException(); - span.recordException(targetException); - span.setStatus(StatusCode.ERROR, targetException.getClass().getSimpleName()); - throw targetException; - } finally { - span.end(); - } - - return result; - } - default: - break; - } - - String requestProxyMethodName = "requestProxy"; - if (requestProxyMethodName.equals(methodName)) { - spanBuilder = ConfigTrace.getClientConfigRpcSpanBuilder("GRPC"); - spanBuilder.setAttribute(SemanticAttributes.CODE_NAMESPACE, - configRpcTransportClient.getClass().getName()); - spanBuilder.setAttribute(SemanticAttributes.CODE_FUNCTION, methodName); - spanBuilder.setAttribute(NacosSemanticAttributes.AGENT_NAME, - configRpcTransportClient.getName()); - spanBuilder.setAttribute(NacosSemanticAttributes.TIMEOUT_MS, - args.length > 2 ? (long) args[2] : 3000L); - - Object result; - Span span = spanBuilder.startSpan(); - - try (Scope ignored = span.makeCurrent()) { - - if (span.isRecording()) { - RpcClient rpcClientInner = (RpcClient) args[0]; - Request request = (Request) args[1]; - // Inject the context into the request headers. - TraceMonitor.getOpenTelemetry().getPropagators().getTextMapPropagator() - .inject(Context.current(), request.getHeaders(), - TraceMonitor.getRpcContextSetter()); - - span.setAttribute(SemanticAttributes.RPC_SYSTEM, - rpcClientInner.getConnectionType().getType().toLowerCase()); - if (rpcClientInner.getCurrentServer() != null) { - span.setAttribute(NacosSemanticAttributes.SERVER_ADDRESS, - rpcClientInner.getCurrentServer().getAddress()); - } - } - - result = method.invoke(configRpcTransportClient, args); - - if (span.isRecording() && result != null) { - Response rpcResponse = (Response) result; - if (rpcResponse.isSuccess()) { - span.setStatus(StatusCode.OK); - } else { - span.setStatus(StatusCode.ERROR, - rpcResponse.getErrorCode() + ": " + rpcResponse.getMessage()); - } - span.setAttribute(SemanticAttributes.RPC_GRPC_STATUS_CODE, rpcResponse.getResultCode()); - } - - } catch (InvocationTargetException e) { - Throwable targetException = e.getTargetException(); - span.recordException(targetException); - span.setStatus(StatusCode.ERROR, targetException.getClass().getSimpleName()); - throw targetException; - } finally { - span.end(); - } - - return result; - } - - try { - return method.invoke(configRpcTransportClient, args); - } catch (InvocationTargetException e) { - throw e.getTargetException(); - } - - }); - } - public static ServerRequestHandler getServerRequestHandlerTraceProxy(ServerRequestHandler serverRequestHandler) { return (ServerRequestHandler) Proxy.newProxyInstance(TraceDynamicProxy.class.getClassLoader(), new Class[] {ServerRequestHandler.class}, (proxy, method, args) -> { diff --git a/client/src/main/java/com/alibaba/nacos/client/monitor/config/ClientWorkerTraceDelegate.java b/client/src/main/java/com/alibaba/nacos/client/monitor/config/ClientWorkerTraceDelegate.java new file mode 100644 index 00000000000..a83ffddfd0d --- /dev/null +++ b/client/src/main/java/com/alibaba/nacos/client/monitor/config/ClientWorkerTraceDelegate.java @@ -0,0 +1,474 @@ +/* + * + * Copyright 1999-2023 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.client.monitor.config; + +import com.alibaba.nacos.api.config.listener.Listener; +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.client.config.filter.impl.ConfigFilterChainManager; +import com.alibaba.nacos.client.config.filter.impl.ConfigResponse; +import com.alibaba.nacos.client.config.impl.CacheData; +import com.alibaba.nacos.client.config.impl.ClientWorker; +import com.alibaba.nacos.client.config.impl.ServerListManager; +import com.alibaba.nacos.client.env.NacosClientProperties; +import com.alibaba.nacos.common.constant.NacosSemanticAttributes; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanBuilder; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.context.Scope; +import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; + +import java.util.List; + +/** + * Opentelemetry Trace delegate for {@link com.alibaba.nacos.client.config.proxy.ClientWorkerProxy}. + * + * @author FAWC438 + */ +public class ClientWorkerTraceDelegate extends ClientWorker { + + public ClientWorkerTraceDelegate(final ConfigFilterChainManager configFilterChainManager, + ServerListManager serverListManager, final NacosClientProperties properties) throws NacosException { + super(configFilterChainManager, serverListManager, properties); + } + + /** + * Init Service level SpanBuilder with method name. + * + * @param methodName method name + * @return SpanBuilder + */ + private SpanBuilder initServiceSpanBuilder(String methodName) { + SpanBuilder spanBuilder = ConfigTrace.getClientConfigServiceSpanBuilder(methodName); + spanBuilder.setAttribute(SemanticAttributes.CODE_NAMESPACE, super.getClass().getName()); + spanBuilder.setAttribute(SemanticAttributes.CODE_FUNCTION, methodName); + spanBuilder.setAttribute(NacosSemanticAttributes.AGENT_NAME, super.getAgentName()); + return spanBuilder; + } + + /** + * Init Worker level SpanBuilder with method name. + * + * @param methodName method name + * @return SpanBuilder + */ + private SpanBuilder initWorkerSpanBuilder(String methodName) { + SpanBuilder spanBuilder = ConfigTrace.getClientConfigWorkerSpanBuilder(methodName); + spanBuilder.setAttribute(SemanticAttributes.CODE_NAMESPACE, super.getClass().getName()); + spanBuilder.setAttribute(SemanticAttributes.CODE_FUNCTION, methodName); + spanBuilder.setAttribute(NacosSemanticAttributes.AGENT_NAME, super.getAgentName()); + return spanBuilder; + } + + /** + * Add listeners for data. + * + * @param dataId dataId of data + * @param group group of data + * @param listeners listeners + */ + @Override + public void addListeners(String dataId, String group, List listeners) throws NacosException { + Span span = initServiceSpanBuilder("addListeners").startSpan(); + try (Scope ignored = span.makeCurrent()) { + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.DATA_ID, dataId); + span.setAttribute(NacosSemanticAttributes.GROUP, group); + } + + group = super.blank2defaultGroup(group); + + CacheData cache = this.addCacheDataIfAbsent(dataId, group); + + synchronized (cache) { + for (Listener listener : listeners) { + cache.addListener(listener); + } + cache.setDiscard(false); + cache.setConsistentWithServer(false); + super.agent.notifyListenConfig(); + } + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, "Add listeners failed"); + throw e; + } finally { + span.end(); + } + } + + /** + * Add listener to config. + * + * @param dataId dataId + * @param group group + * @param content content + * @param encryptedDataKey encryptedDataKey + * @param listeners listener + * @throws NacosException NacosException + */ + @Override + public void addTenantListenersWithContent(String dataId, String group, String content, String encryptedDataKey, + List listeners) throws NacosException { + Span span = initServiceSpanBuilder("addTenantListenersWithContent").startSpan(); + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.DATA_ID, dataId); + span.setAttribute(NacosSemanticAttributes.GROUP, group); + span.setAttribute(NacosSemanticAttributes.CONTENT, content); + } + + group = super.blank2defaultGroup(group); + String tenant = super.agent.getTenant(); + + CacheData cache = this.addCacheDataIfAbsent(dataId, group, tenant); + + synchronized (cache) { + cache.setEncryptedDataKey(encryptedDataKey); + cache.setContent(content); + for (Listener listener : listeners) { + cache.addListener(listener); + } + cache.setDiscard(false); + cache.setConsistentWithServer(false); + super.agent.notifyListenConfig(); + } + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Add listener to config. + * + * @param dataId dataId + * @param group group + * @param listeners listener + * @throws NacosException NacosException + */ + @Override + public void addTenantListeners(String dataId, String group, List listeners) + throws NacosException { + Span span = initServiceSpanBuilder("addTenantListeners").startSpan(); + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.DATA_ID, dataId); + span.setAttribute(NacosSemanticAttributes.GROUP, group); + } + + group = super.blank2defaultGroup(group); + String tenant = super.agent.getTenant(); + + CacheData cache = this.addCacheDataIfAbsent(dataId, group, tenant); + + synchronized (cache) { + for (Listener listener : listeners) { + cache.addListener(listener); + } + cache.setDiscard(false); + cache.setConsistentWithServer(false); + super.agent.notifyListenConfig(); + } + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Remove listener from config. + * + * @param dataId dataId + * @param group group + * @param listener listener + */ + @Override + public void removeTenantListener(String dataId, String group, Listener listener) { + Span span = initServiceSpanBuilder("removeTenantListener").startSpan(); + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.DATA_ID, dataId); + span.setAttribute(NacosSemanticAttributes.GROUP, group); + } + + super.removeTenantListener(dataId, group, listener); + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Remove all listeners from config. + * + * @param dataId dataId + * @param group group + * @param tenant tenant + * @param readTimeout readTimeout + * @param notify notify + * @return ConfigResponse + * @throws NacosException NacosException + */ + @Override + public ConfigResponse getServerConfig(String dataId, String group, String tenant, long readTimeout, boolean notify) + throws NacosException { + Span span = initServiceSpanBuilder("getServerConfig").startSpan(); + ConfigResponse result; + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.DATA_ID, dataId); + span.setAttribute(NacosSemanticAttributes.GROUP, group); + span.setAttribute(NacosSemanticAttributes.TENANT, tenant); + span.setAttribute(NacosSemanticAttributes.TIMEOUT_MS, readTimeout); + span.setAttribute(NacosSemanticAttributes.NOTIFY, notify); + } + + result = super.getServerConfig(dataId, group, tenant, readTimeout, notify); + + if (span.isRecording() && result != null) { + span.setAttribute(NacosSemanticAttributes.CONTENT, result.getContent()); + } + return result; + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Remove all listeners from config. + * + * @param dataId dataId + * @param group group + * @param tenant tenant + * @param tag tag + * @return boolean + * @throws NacosException NacosException + */ + @Override + public boolean removeConfig(String dataId, String group, String tenant, String tag) throws NacosException { + Span span = initServiceSpanBuilder("removeConfig").startSpan(); + boolean result; + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.DATA_ID, dataId); + span.setAttribute(NacosSemanticAttributes.GROUP, group); + span.setAttribute(NacosSemanticAttributes.TENANT, tenant); + span.setAttribute(NacosSemanticAttributes.TAG, tag); + } + + result = super.removeConfig(dataId, group, tenant, tag); + + if (span.isRecording()) { + if (result) { + span.setStatus(StatusCode.OK, "Remove config success"); + } else { + span.setStatus(StatusCode.ERROR, "Remove config failed"); + } + } + return result; + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Remove all listeners from config. + * + * @param dataId dataId + * @param group group + * @param tenant tenant + * @param appName appName + * @param tag tag + * @param betaIps betaIps + * @param content content + * @param encryptedDataKey encryptedDataKey + * @param casMd5 casMd5 + * @param type type + * @return boolean + * @throws NacosException NacosException + */ + @Override + public boolean publishConfig(String dataId, String group, String tenant, String appName, String tag, String betaIps, + String content, String encryptedDataKey, String casMd5, String type) throws NacosException { + Span span = initServiceSpanBuilder("publishConfig").startSpan(); + boolean result; + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.DATA_ID, dataId); + span.setAttribute(NacosSemanticAttributes.GROUP, group); + span.setAttribute(NacosSemanticAttributes.TENANT, tenant); + span.setAttribute(NacosSemanticAttributes.APPLICATION_NAME, appName); + span.setAttribute(NacosSemanticAttributes.TAG, tag); + span.setAttribute(NacosSemanticAttributes.CONTENT, content); + span.setAttribute(NacosSemanticAttributes.CONFIG_TYPE, type); + } + + result = super.publishConfig(dataId, group, tenant, appName, tag, betaIps, content, encryptedDataKey, + casMd5, type); + + if (span.isRecording()) { + if (result) { + span.setStatus(StatusCode.OK, "Publish config success"); + } else { + span.setStatus(StatusCode.ERROR, "Publish config failed"); + } + } + return result; + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Add cache data if absent. + * + * @param dataId data id if data + * @param group group of data + * @return cache data + */ + @Override + public CacheData addCacheDataIfAbsent(String dataId, String group) { + Span span = initWorkerSpanBuilder("addCacheDataIfAbsent").startSpan(); + CacheData result; + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.DATA_ID, dataId); + span.setAttribute(NacosSemanticAttributes.GROUP, group); + span.setAttribute(NacosSemanticAttributes.TENANT, super.getAgentTenant()); + } + + result = super.addCacheDataIfAbsent(dataId, group); + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.CONTENT, result.getContent()); + } + return result; + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Add cache data if absent. + * + * @param dataId data id if data + * @param group group of data + * @param tenant tenant of data + * @return cache data + * @throws NacosException NacosException + */ + @Override + public CacheData addCacheDataIfAbsent(String dataId, String group, String tenant) throws NacosException { + Span span = initWorkerSpanBuilder("addCacheDataIfAbsent").startSpan(); + CacheData result; + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.DATA_ID, dataId); + span.setAttribute(NacosSemanticAttributes.GROUP, group); + span.setAttribute(NacosSemanticAttributes.TENANT, tenant); + } + + result = super.addCacheDataIfAbsent(dataId, group, tenant); + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.CONTENT, result.getContent()); + } + return result; + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Check whether the server is health. + * + * @return boolean + */ + @Override + public boolean isHealthServer() { + Span span = initServiceSpanBuilder("isHealthServer").startSpan(); + boolean result; + try (Scope ignored = span.makeCurrent()) { + + result = super.isHealthServer(); + + if (span.isRecording()) { + if (result) { + span.setStatus(StatusCode.OK, "Server is healthy"); + } else { + span.setStatus(StatusCode.ERROR, "Server is not healthy"); + } + } + return result; + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, "Server is not health"); + throw e; + } finally { + span.end(); + } + } +} diff --git a/client/src/main/java/com/alibaba/nacos/client/monitor/config/ConfigRpcTransportClientProxyTraceDelegate.java b/client/src/main/java/com/alibaba/nacos/client/monitor/config/ConfigRpcTransportClientProxyTraceDelegate.java new file mode 100644 index 00000000000..173fc7f7c46 --- /dev/null +++ b/client/src/main/java/com/alibaba/nacos/client/monitor/config/ConfigRpcTransportClientProxyTraceDelegate.java @@ -0,0 +1,363 @@ +/* + * + * Copyright 1999-2023 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.client.monitor.config; + +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.remote.request.Request; +import com.alibaba.nacos.api.remote.response.Response; +import com.alibaba.nacos.client.config.filter.impl.ConfigResponse; +import com.alibaba.nacos.client.config.impl.ServerListManager; +import com.alibaba.nacos.client.config.proxy.ConfigRpcTransportClientProxy; +import com.alibaba.nacos.client.monitor.TraceMonitor; +import com.alibaba.nacos.common.constant.NacosSemanticAttributes; +import com.alibaba.nacos.common.remote.client.RpcClient; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanBuilder; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; + +import java.util.concurrent.ScheduledExecutorService; + +/** + * Opentelemetry Trace delegate for {@link com.alibaba.nacos.client.config.impl.ClientWorker.ConfigRpcTransportClient}. + * + * @author FAWC438 + */ +public class ConfigRpcTransportClientProxyTraceDelegate implements ConfigRpcTransportClientProxy { + + private final ConfigRpcTransportClientProxy configRpcTransportClientImpl; + + public ConfigRpcTransportClientProxyTraceDelegate(ConfigRpcTransportClientProxy impl) { + this.configRpcTransportClientImpl = impl; + } + + /** + * Init Worker level SpanBuilder with method name. + * + * @param methodName method name + * @return SpanBuilder + */ + private SpanBuilder initWorkerSpanBuilder(String methodName) { + SpanBuilder spanBuilder = ConfigTrace.getClientConfigWorkerSpanBuilder(methodName); + spanBuilder.setAttribute(SemanticAttributes.CODE_NAMESPACE, + this.configRpcTransportClientImpl.getClass().getName()); + spanBuilder.setAttribute(SemanticAttributes.CODE_FUNCTION, methodName); + spanBuilder.setAttribute(NacosSemanticAttributes.AGENT_NAME, this.configRpcTransportClientImpl.getName()); + return spanBuilder; + } + + /** + * Init Rpc level SpanBuilder with method name. + * + * @param methodName method name + * @return SpanBuilder + */ + private SpanBuilder initRpcSpanBuilder(String methodName) { + SpanBuilder spanBuilder = ConfigTrace.getClientConfigRpcSpanBuilder(methodName); + spanBuilder.setAttribute(SemanticAttributes.CODE_NAMESPACE, + this.configRpcTransportClientImpl.getClass().getName()); + spanBuilder.setAttribute(SemanticAttributes.CODE_FUNCTION, methodName); + spanBuilder.setAttribute(NacosSemanticAttributes.AGENT_NAME, this.configRpcTransportClientImpl.getName()); + return spanBuilder; + } + + /** + * Query config from server. + * + * @param dataId dataId + * @param group group + * @param tenant tenant + * @param readTimeouts readTimeouts + * @param notify notify + * @return ConfigResponse + * @throws NacosException NacosException + */ + @Override + public ConfigResponse queryConfig(String dataId, String group, String tenant, long readTimeouts, boolean notify) + throws NacosException { + Span span = initWorkerSpanBuilder("queryConfig").startSpan(); + ConfigResponse result; + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.DATA_ID, dataId); + span.setAttribute(NacosSemanticAttributes.GROUP, group); + span.setAttribute(NacosSemanticAttributes.TENANT, tenant); + span.setAttribute(NacosSemanticAttributes.TIMEOUT_MS, readTimeouts); + span.setAttribute(NacosSemanticAttributes.NOTIFY, notify); + } + + result = this.configRpcTransportClientImpl.queryConfig(dataId, group, tenant, readTimeouts, notify); + + if (span.isRecording()) { + if (result == null || result.getConfigType() == null) { + span.setStatus(StatusCode.ERROR, "Config not found"); + } else { + span.setStatus(StatusCode.OK, "Query Config success"); + } + } + return result; + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Publish config to server. + * + * @param dataId dataId + * @param group group + * @param tenant tenant + * @param appName appName + * @param tag tag + * @param betaIps betaIps + * @param content content + * @param encryptedDataKey encryptedDataKey + * @param casMd5 casMd5 + * @param type type + * @return boolean + * @throws NacosException NacosException + */ + @Override + public boolean publishConfig(String dataId, String group, String tenant, String appName, String tag, String betaIps, + String content, String encryptedDataKey, String casMd5, String type) throws NacosException { + Span span = initWorkerSpanBuilder("publishConfig").startSpan(); + boolean result; + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.DATA_ID, dataId); + span.setAttribute(NacosSemanticAttributes.GROUP, group); + span.setAttribute(NacosSemanticAttributes.TENANT, tenant); + span.setAttribute(NacosSemanticAttributes.APPLICATION_NAME, appName); + span.setAttribute(NacosSemanticAttributes.TAG, tag); + span.setAttribute(NacosSemanticAttributes.CONTENT, content); + span.setAttribute(NacosSemanticAttributes.CONFIG_TYPE, type); + } + + result = this.configRpcTransportClientImpl.publishConfig(dataId, group, tenant, appName, tag, betaIps, + content, encryptedDataKey, casMd5, type); + + if (span.isRecording()) { + if (result) { + span.setStatus(StatusCode.OK, "Publish Config success"); + } else { + span.setStatus(StatusCode.ERROR, "Publish Config failed"); + } + } + return result; + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Remove config from server. + * + * @param dataId dataId + * @param group group + * @param tenant tenant + * @param tag tag + * @return boolean + * @throws NacosException NacosException + */ + @Override + public boolean removeConfig(String dataId, String group, String tenant, String tag) throws NacosException { + Span span = initWorkerSpanBuilder("removeConfig").startSpan(); + boolean result; + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.DATA_ID, dataId); + span.setAttribute(NacosSemanticAttributes.GROUP, group); + span.setAttribute(NacosSemanticAttributes.TENANT, tenant); + span.setAttribute(NacosSemanticAttributes.TAG, tag); + } + + result = this.configRpcTransportClientImpl.removeConfig(dataId, group, tenant, tag); + + if (span.isRecording()) { + if (result) { + span.setStatus(StatusCode.OK, "Remove Config success"); + } else { + span.setStatus(StatusCode.ERROR, "Remove Config failed"); + } + } + return result; + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Request proxy. + * + * @param rpcClientInner rpcClientInner + * @param request request + * @param timeoutMills timeoutMills + * @return Response + * @throws NacosException NacosException + */ + @Override + public Response requestProxy(RpcClient rpcClientInner, Request request, long timeoutMills) throws NacosException { + Span span = initRpcSpanBuilder("requestProxy").startSpan(); + Response result; + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.TIMEOUT_MS, timeoutMills); + span.setAttribute(SemanticAttributes.RPC_SYSTEM, + rpcClientInner.getConnectionType().getType().toLowerCase()); + if (rpcClientInner.getCurrentServer() != null) { + span.setAttribute(NacosSemanticAttributes.SERVER_ADDRESS, + rpcClientInner.getCurrentServer().getAddress()); + } + TraceMonitor.getOpenTelemetry().getPropagators().getTextMapPropagator() + .inject(Context.current(), request.getHeaders(), TraceMonitor.getRpcContextSetter()); + } + + result = this.configRpcTransportClientImpl.requestProxy(rpcClientInner, request, timeoutMills); + + if (span.isRecording()) { + if (result == null) { + span.setStatus(StatusCode.ERROR, "Request failed: result is null"); + } else if (result.isSuccess()) { + span.setStatus(StatusCode.OK, "Request success"); + } else { + span.setStatus(StatusCode.ERROR, + "Request failed: " + result.getErrorCode() + ": " + result.getMessage()); + } + } + return result; + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Notify listen config. + */ + @Override + public void notifyListenConfig() { + this.configRpcTransportClientImpl.notifyListenConfig(); + } + + /** + * Get tenant. + * + * @return tenant + */ + @Override + public String getTenant() { + return this.configRpcTransportClientImpl.getTenant(); + } + + /** + * Remove cache. + * + * @param dataId dataId + * @param group group + */ + @Override + public void removeCache(String dataId, String group) { + this.configRpcTransportClientImpl.removeCache(dataId, group); + } + + /** + * Get agent name. + * + * @return agent name + */ + @Override + public String getName() { + return this.configRpcTransportClientImpl.getName(); + } + + /** + * Get server list manager. + * + * @return server list manager + */ + @Override + public ServerListManager getServerListManager() { + return this.configRpcTransportClientImpl.getServerListManager(); + } + + /** + * Set executor. + * + * @param executor executor + */ + @Override + public void setExecutor(ScheduledExecutorService executor) { + this.configRpcTransportClientImpl.setExecutor(executor); + } + + /** + * Start agent. + * + * @throws NacosException NacosException + */ + @Override + public void start() throws NacosException { + this.configRpcTransportClientImpl.start(); + } + + /** + * Check whether the server is health. + * + * @return boolean + */ + @Override + public boolean isHealthServer() { + return this.configRpcTransportClientImpl.isHealthServer(); + } + + /** + * Shutdown the Resources, such as Thread Pool. + * + * @throws NacosException exception. + */ + @Override + public void shutdown() throws NacosException { + this.configRpcTransportClientImpl.shutdown(); + } +} diff --git a/client/src/test/java/com/alibaba/nacos/client/monitor/TraceDynamicProxyTest.java b/client/src/test/java/com/alibaba/nacos/client/monitor/TraceDynamicProxyTest.java index 737a183a2eb..3c89bda36fd 100644 --- a/client/src/test/java/com/alibaba/nacos/client/monitor/TraceDynamicProxyTest.java +++ b/client/src/test/java/com/alibaba/nacos/client/monitor/TraceDynamicProxyTest.java @@ -33,7 +33,7 @@ import com.alibaba.nacos.client.config.impl.ClientWorker; import com.alibaba.nacos.client.config.impl.ServerListManager; import com.alibaba.nacos.client.env.NacosClientProperties; -import com.alibaba.nacos.client.monitor.config.ClientWorkerTraceProxy; +import com.alibaba.nacos.client.config.proxy.ClientWorkerProxy; import com.alibaba.nacos.client.monitor.naming.NamingGrpcRedoServiceTraceProxy; import com.alibaba.nacos.client.naming.cache.ServiceInfoHolder; import com.alibaba.nacos.client.naming.core.ServiceInfoUpdateService; @@ -93,7 +93,7 @@ public void testGetClientWorkerTraceProxyListener() throws NacosException { final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(prop); ClientWorker clientWorker = new ClientWorker(filter, serverListManager, nacosClientProperties); - ClientWorkerTraceProxy traceProxy = TraceDynamicProxy.getClientWorkerTraceProxy(clientWorker); + ClientWorkerProxy traceProxy = TraceDynamicProxy.getClientWorkerTraceProxy(clientWorker); Listener listener = new AbstractListener() { @Override @@ -135,7 +135,7 @@ public void testGetClientWorkerTraceProxyConfig() throws NacosException { final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(prop); ClientWorker clientWorker = new ClientWorker(filter, serverListManager, nacosClientProperties); - ClientWorkerTraceProxy traceProxy = TraceDynamicProxy.getClientWorkerTraceProxy(clientWorker); + ClientWorkerProxy traceProxy = TraceDynamicProxy.getClientWorkerTraceProxy(clientWorker); String dataId = "a"; String group = "b"; @@ -196,7 +196,7 @@ public void testGetClientWorkerTraceProxyIsHealthServer() declaredField.setAccessible(true); declaredField.set(clientWorker, client); - ClientWorkerTraceProxy traceProxy = TraceDynamicProxy.getClientWorkerTraceProxy(clientWorker); + ClientWorkerProxy traceProxy = TraceDynamicProxy.getClientWorkerTraceProxy(clientWorker); Assert.assertTrue(traceProxy.isHealthServer()); Assert.assertEquals("Nacos.client.config.service / isHealthServer", @@ -213,7 +213,7 @@ public void testGetConfigRpcTransportClientTraceProxy() throws NacosException { final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(prop); ClientWorker clientWorker = new ClientWorker(filter, serverListManager, nacosClientProperties); - ClientWorkerTraceProxy traceProxy = TraceDynamicProxy.getClientWorkerTraceProxy(clientWorker); + ClientWorkerProxy traceProxy = TraceDynamicProxy.getClientWorkerTraceProxy(clientWorker); String dataId = "a"; String group = "b"; From af935c5743d4ac4faa051ed064ea8ae20ac9c812 Mon Sep 17 00:00:00 2001 From: FAWC438 Date: Thu, 21 Dec 2023 18:32:15 +0800 Subject: [PATCH 2/5] Migrate all dynamic proxy to delegate class --- .../client/config/NacosConfigService.java | 7 +- .../client/config/http/ServerHttpAgent.java | 2 +- .../client/config/impl/ClientWorker.java | 108 ++-- .../client/monitor/TraceDynamicProxy.java | 97 +-- .../ServerRequestHandlerTraceDelegate.java | 116 ++++ .../delegate/config}/ClientWorkerProxy.java | 2 +- .../config/ClientWorkerTraceDelegate.java | 227 +++---- .../ConfigRpcTransportClientProxy.java | 2 +- ...gRpcTransportClientProxyTraceDelegate.java | 4 +- .../config/ServerHttpAgentTraceDelegate.java | 164 +++++ .../NamingClientProxyTraceDelegate.java | 594 ++++++++++++++++++ .../NamingGrpcRedoServiceTraceDelegate.java | 376 +++++++++++ .../client/naming/NacosNamingService.java | 4 +- .../remote/NamingClientProxyDelegate.java | 6 +- .../remote/gprc/NamingGrpcClientProxy.java | 15 +- .../gprc/redo/NamingGrpcRedoService.java | 16 +- .../client/monitor/TraceDynamicProxyTest.java | 2 +- 17 files changed, 1424 insertions(+), 318 deletions(-) create mode 100644 client/src/main/java/com/alibaba/nacos/client/monitor/delegate/ServerRequestHandlerTraceDelegate.java rename client/src/main/java/com/alibaba/nacos/client/{config/proxy => monitor/delegate/config}/ClientWorkerProxy.java (98%) rename client/src/main/java/com/alibaba/nacos/client/monitor/{ => delegate}/config/ClientWorkerTraceDelegate.java (72%) rename client/src/main/java/com/alibaba/nacos/client/{config/proxy => monitor/delegate/config}/ConfigRpcTransportClientProxy.java (98%) rename client/src/main/java/com/alibaba/nacos/client/monitor/{ => delegate}/config/ConfigRpcTransportClientProxyTraceDelegate.java (99%) create mode 100644 client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ServerHttpAgentTraceDelegate.java create mode 100644 client/src/main/java/com/alibaba/nacos/client/monitor/delegate/naming/NamingClientProxyTraceDelegate.java create mode 100644 client/src/main/java/com/alibaba/nacos/client/monitor/delegate/naming/NamingGrpcRedoServiceTraceDelegate.java diff --git a/client/src/main/java/com/alibaba/nacos/client/config/NacosConfigService.java b/client/src/main/java/com/alibaba/nacos/client/config/NacosConfigService.java index f94549127ce..7c484100d53 100644 --- a/client/src/main/java/com/alibaba/nacos/client/config/NacosConfigService.java +++ b/client/src/main/java/com/alibaba/nacos/client/config/NacosConfigService.java @@ -27,7 +27,6 @@ import com.alibaba.nacos.client.config.filter.impl.ConfigRequest; import com.alibaba.nacos.client.config.filter.impl.ConfigResponse; import com.alibaba.nacos.client.config.http.HttpAgent; -import com.alibaba.nacos.client.config.http.ServerHttpAgent; import com.alibaba.nacos.client.config.impl.ClientWorker; import com.alibaba.nacos.client.config.impl.LocalConfigInfoProcessor; import com.alibaba.nacos.client.config.impl.LocalEncryptedDataKeyProcessor; @@ -35,9 +34,9 @@ import com.alibaba.nacos.client.config.utils.ContentUtils; import com.alibaba.nacos.client.config.utils.ParamUtils; import com.alibaba.nacos.client.env.NacosClientProperties; -import com.alibaba.nacos.client.monitor.TraceDynamicProxy; -import com.alibaba.nacos.client.monitor.config.ClientWorkerTraceDelegate; import com.alibaba.nacos.client.monitor.config.ConfigTrace; +import com.alibaba.nacos.client.monitor.delegate.config.ClientWorkerTraceDelegate; +import com.alibaba.nacos.client.monitor.delegate.config.ServerHttpAgentTraceDelegate; import com.alibaba.nacos.client.utils.LogUtils; import com.alibaba.nacos.client.utils.ParamUtil; import com.alibaba.nacos.client.utils.ValidatorUtils; @@ -93,7 +92,7 @@ public NacosConfigService(Properties properties) throws NacosException { this.worker = new ClientWorkerTraceDelegate(this.configFilterChainManager, serverListManager, clientProperties); // will be deleted in 2.0 later versions - agent = TraceDynamicProxy.getHttpAgentTraceProxy(new ServerHttpAgent(serverListManager)); + agent = new ServerHttpAgentTraceDelegate(serverListManager); } diff --git a/client/src/main/java/com/alibaba/nacos/client/config/http/ServerHttpAgent.java b/client/src/main/java/com/alibaba/nacos/client/config/http/ServerHttpAgent.java index 7ef401f7a6e..50d32ed4d6d 100644 --- a/client/src/main/java/com/alibaba/nacos/client/config/http/ServerHttpAgent.java +++ b/client/src/main/java/com/alibaba/nacos/client/config/http/ServerHttpAgent.java @@ -239,7 +239,7 @@ private String getUrl(String serverAddr, String relativePath) { return serverAddr + ContextPathUtil.normalizeContextPath(serverListMgr.getContentPath()) + relativePath; } - private boolean isFail(HttpRestResult result) { + protected boolean isFail(HttpRestResult result) { return result.getCode() == HttpURLConnection.HTTP_INTERNAL_ERROR || result.getCode() == HttpURLConnection.HTTP_BAD_GATEWAY || result.getCode() == HttpURLConnection.HTTP_UNAVAILABLE diff --git a/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java b/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java index e6c3d5a3e51..0fc328cc131 100644 --- a/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java +++ b/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java @@ -42,11 +42,12 @@ import com.alibaba.nacos.client.config.filter.impl.ConfigResponse; import com.alibaba.nacos.client.config.utils.ContentUtils; import com.alibaba.nacos.client.env.NacosClientProperties; -import com.alibaba.nacos.client.monitor.TraceDynamicProxy; -import com.alibaba.nacos.client.config.proxy.ClientWorkerProxy; import com.alibaba.nacos.client.monitor.config.ConfigMetrics; -import com.alibaba.nacos.client.config.proxy.ConfigRpcTransportClientProxy; -import com.alibaba.nacos.client.monitor.config.ConfigRpcTransportClientProxyTraceDelegate; +import com.alibaba.nacos.client.monitor.delegate.ServerRequestHandlerTraceDelegate; +import com.alibaba.nacos.client.monitor.delegate.config.ClientWorkerProxy; +import com.alibaba.nacos.client.monitor.delegate.config.ClientWorkerTraceDelegate; +import com.alibaba.nacos.client.monitor.delegate.config.ConfigRpcTransportClientProxy; +import com.alibaba.nacos.client.monitor.delegate.config.ConfigRpcTransportClientProxyTraceDelegate; import com.alibaba.nacos.client.naming.utils.CollectionUtils; import com.alibaba.nacos.client.utils.AppNameUtils; import com.alibaba.nacos.client.utils.EnvUtil; @@ -155,7 +156,8 @@ public class ClientWorker implements ClientWorkerProxy { public void addListeners(String dataId, String group, List listeners) throws NacosException { group = blank2defaultGroup(group); - CacheData cache = addCacheDataIfAbsent(dataId, group); + // addCacheDataIfAbsent + CacheData cache = ClientWorkerTraceDelegate.AddCacheDataWarp.warp(this, dataId, group); synchronized (cache) { @@ -183,7 +185,8 @@ public void addTenantListeners(String dataId, String group, List { - if (request instanceof ConfigChangeNotifyRequest) { - final long start = System.currentTimeMillis(); - - ConfigChangeNotifyRequest configChangeNotifyRequest = (ConfigChangeNotifyRequest) request; - LOGGER.info("[{}] [server-push] config changed. dataId={}, group={},tenant={}", - rpcClientInner.getName(), configChangeNotifyRequest.getDataId(), - configChangeNotifyRequest.getGroup(), configChangeNotifyRequest.getTenant()); - String groupKey = GroupKey.getKeyTenant(configChangeNotifyRequest.getDataId(), - configChangeNotifyRequest.getGroup(), configChangeNotifyRequest.getTenant()); - - CacheData cacheData = cacheMap.get().get(groupKey); - if (cacheData != null) { - synchronized (cacheData) { - cacheData.getReceiveNotifyChanged().set(true); - cacheData.setConsistentWithServer(false); - notifyListenConfig(); - } - } - - // metrics - ConfigMetrics.incServerRequestHandleCounter(); - ConfigMetrics.recordHandleServerRequestCostDurationTimer( - ConfigChangeNotifyRequest.class.getSimpleName(), - System.currentTimeMillis() - start); - - return new ConfigChangeNotifyResponse(); + rpcClientInner.registerServerRequestHandler(ServerRequestHandlerTraceDelegate.warp((request) -> { + if (request instanceof ConfigChangeNotifyRequest) { + final long start = System.currentTimeMillis(); + + ConfigChangeNotifyRequest configChangeNotifyRequest = (ConfigChangeNotifyRequest) request; + LOGGER.info("[{}] [server-push] config changed. dataId={}, group={},tenant={}", + rpcClientInner.getName(), configChangeNotifyRequest.getDataId(), + configChangeNotifyRequest.getGroup(), configChangeNotifyRequest.getTenant()); + String groupKey = GroupKey.getKeyTenant(configChangeNotifyRequest.getDataId(), + configChangeNotifyRequest.getGroup(), configChangeNotifyRequest.getTenant()); + + CacheData cacheData = cacheMap.get().get(groupKey); + if (cacheData != null) { + synchronized (cacheData) { + cacheData.getReceiveNotifyChanged().set(true); + cacheData.setConsistentWithServer(false); + notifyListenConfig(); } - return null; - })); + } + + // metrics + ConfigMetrics.incServerRequestHandleCounter(); + ConfigMetrics.recordHandleServerRequestCostDurationTimer( + ConfigChangeNotifyRequest.class.getSimpleName(), System.currentTimeMillis() - start); + + return new ConfigChangeNotifyResponse(); + } + return null; + })); - rpcClientInner.registerServerRequestHandler( - TraceDynamicProxy.getServerRequestHandlerTraceProxy((request) -> { - if (request instanceof ClientConfigMetricRequest) { - final long start = System.currentTimeMillis(); - - ClientConfigMetricResponse response = new ClientConfigMetricResponse(); - response.setMetrics(getMetrics(((ClientConfigMetricRequest) request).getMetricsKeys())); - - // metrics - ConfigMetrics.incServerRequestHandleCounter(); - ConfigMetrics.recordHandleServerRequestCostDurationTimer( - ClientConfigMetricRequest.class.getSimpleName(), - System.currentTimeMillis() - start); - return response; - } - return null; - })); + rpcClientInner.registerServerRequestHandler(ServerRequestHandlerTraceDelegate.warp((request) -> { + if (request instanceof ClientConfigMetricRequest) { + final long start = System.currentTimeMillis(); + + ClientConfigMetricResponse response = new ClientConfigMetricResponse(); + response.setMetrics(getMetrics(((ClientConfigMetricRequest) request).getMetricsKeys())); + + // metrics + ConfigMetrics.incServerRequestHandleCounter(); + ConfigMetrics.recordHandleServerRequestCostDurationTimer( + ClientConfigMetricRequest.class.getSimpleName(), System.currentTimeMillis() - start); + return response; + } + return null; + })); rpcClientInner.registerConnectionListener(new ConnectionEventListener() { diff --git a/client/src/main/java/com/alibaba/nacos/client/monitor/TraceDynamicProxy.java b/client/src/main/java/com/alibaba/nacos/client/monitor/TraceDynamicProxy.java index 35c15fc29ff..b52435b7dfd 100644 --- a/client/src/main/java/com/alibaba/nacos/client/monitor/TraceDynamicProxy.java +++ b/client/src/main/java/com/alibaba/nacos/client/monitor/TraceDynamicProxy.java @@ -18,20 +18,16 @@ package com.alibaba.nacos.client.monitor; -import com.alibaba.nacos.api.config.remote.request.ClientConfigMetricRequest; -import com.alibaba.nacos.api.config.remote.request.ConfigChangeNotifyRequest; import com.alibaba.nacos.api.naming.pojo.Instance; import com.alibaba.nacos.api.naming.pojo.Service; -import com.alibaba.nacos.api.naming.remote.request.NotifySubscriberRequest; import com.alibaba.nacos.api.naming.remote.response.QueryServiceResponse; import com.alibaba.nacos.api.naming.remote.response.ServiceListResponse; -import com.alibaba.nacos.api.remote.request.Request; import com.alibaba.nacos.client.config.filter.impl.ConfigResponse; import com.alibaba.nacos.client.config.http.HttpAgent; import com.alibaba.nacos.client.config.impl.CacheData; import com.alibaba.nacos.client.config.impl.ClientWorker; -import com.alibaba.nacos.client.config.proxy.ClientWorkerProxy; import com.alibaba.nacos.client.monitor.config.ConfigTrace; +import com.alibaba.nacos.client.monitor.delegate.config.ClientWorkerProxy; import com.alibaba.nacos.client.monitor.naming.NamingGrpcRedoServiceTraceProxy; import com.alibaba.nacos.client.monitor.naming.NamingTrace; import com.alibaba.nacos.client.naming.remote.NamingClientProxy; @@ -41,13 +37,10 @@ import com.alibaba.nacos.client.naming.remote.http.NamingHttpClientProxy; import com.alibaba.nacos.common.constant.NacosSemanticAttributes; import com.alibaba.nacos.common.http.HttpRestResult; -import com.alibaba.nacos.common.remote.client.ServerRequestHandler; import com.alibaba.nacos.common.utils.HttpMethod; import com.alibaba.nacos.common.utils.StringUtils; -import com.alibaba.nacos.common.utils.VersionUtils; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanBuilder; -import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.api.trace.StatusCode; import io.opentelemetry.context.Scope; import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; @@ -307,94 +300,6 @@ public static ClientWorkerProxy getClientWorkerTraceProxy(ClientWorker clientWor }); } - public static ServerRequestHandler getServerRequestHandlerTraceProxy(ServerRequestHandler serverRequestHandler) { - return (ServerRequestHandler) Proxy.newProxyInstance(TraceDynamicProxy.class.getClassLoader(), - new Class[] {ServerRequestHandler.class}, (proxy, method, args) -> { - String methodName = method.getName(); - - String requestReplyMethodName = "requestReply"; - if (requestReplyMethodName.equals(methodName) && args[0] != null) { - - Object result; - Request request = (Request) args[0]; - String moduleName = request.getModule(); - - String spanName = TraceMonitor.getNacosClientRequestFromServerSpanName() + " / " + moduleName; - SpanBuilder spanBuilder = TraceMonitor.getTracer().spanBuilder(spanName); - - // SpanKind.SERVER means incoming span rather than the span in the server side. - // See https://opentelemetry.io/docs/specs/otel/trace/api/#spankind - spanBuilder.setSpanKind(SpanKind.SERVER); - spanBuilder.setAttribute(NacosSemanticAttributes.CLIENT_VERSION, - VersionUtils.getFullClientVersion()); - spanBuilder.setAttribute(SemanticAttributes.CODE_NAMESPACE, - serverRequestHandler.getClass().getName()); - spanBuilder.setAttribute(SemanticAttributes.CODE_FUNCTION, methodName); - spanBuilder.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_ID, - request.getRequestId()); - spanBuilder.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_MODULE, moduleName); - - Span span = spanBuilder.startSpan(); - try (Scope ignored = span.makeCurrent()) { - - if (span.isRecording()) { - if (request instanceof ConfigChangeNotifyRequest) { - ConfigChangeNotifyRequest configChangeNotifyRequest = (ConfigChangeNotifyRequest) request; - span.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_ID, - configChangeNotifyRequest.getRequestId()); - span.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_DATA_ID, - configChangeNotifyRequest.getDataId()); - span.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_GROUP, - configChangeNotifyRequest.getGroup()); - span.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_TENANT, - configChangeNotifyRequest.getTenant()); - span.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_TYPE, - ConfigChangeNotifyRequest.class.getSimpleName()); - - } else if (request instanceof ClientConfigMetricRequest) { - span.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_TYPE, - ClientConfigMetricRequest.class.getSimpleName()); - - } else if (request instanceof NotifySubscriberRequest) { - NotifySubscriberRequest notifySubscriberRequest = (NotifySubscriberRequest) request; - span.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_NAMESPACE, - notifySubscriberRequest.getNamespace()); - span.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_SERVICE_NAME, - notifySubscriberRequest.getServiceName()); - if (notifySubscriberRequest.getServiceInfo() != null) { - span.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_GROUP, - notifySubscriberRequest.getServiceInfo().getGroupName()); - span.setAttribute( - NacosSemanticAttributes.RequestAttributes.REQUEST_SERVICE_CLUSTER_NAME, - notifySubscriberRequest.getServiceInfo().getClusters()); - } - span.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_TYPE, - NotifySubscriberRequest.class.getSimpleName()); - - } - } - - result = method.invoke(serverRequestHandler, args); - - } catch (InvocationTargetException e) { - Throwable targetException = e.getTargetException(); - span.recordException(targetException); - span.setStatus(StatusCode.ERROR, targetException.getClass().getSimpleName()); - throw targetException; - } finally { - span.end(); - } - return result; - } - - try { - return method.invoke(serverRequestHandler, args); - } catch (InvocationTargetException e) { - throw e.getTargetException(); - } - }); - } - public static HttpAgent getHttpAgentTraceProxy(HttpAgent httpAgent) { return (HttpAgent) Proxy.newProxyInstance(TraceDynamicProxy.class.getClassLoader(), new Class[] {HttpAgent.class}, (proxy, method, args) -> { diff --git a/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/ServerRequestHandlerTraceDelegate.java b/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/ServerRequestHandlerTraceDelegate.java new file mode 100644 index 00000000000..76e5951a832 --- /dev/null +++ b/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/ServerRequestHandlerTraceDelegate.java @@ -0,0 +1,116 @@ +/* + * + * Copyright 1999-2023 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.client.monitor.delegate; + +import com.alibaba.nacos.api.config.remote.request.ClientConfigMetricRequest; +import com.alibaba.nacos.api.config.remote.request.ConfigChangeNotifyRequest; +import com.alibaba.nacos.api.naming.remote.request.NotifySubscriberRequest; +import com.alibaba.nacos.client.monitor.TraceMonitor; +import com.alibaba.nacos.common.constant.NacosSemanticAttributes; +import com.alibaba.nacos.common.remote.client.ServerRequestHandler; +import com.alibaba.nacos.common.utils.VersionUtils; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanBuilder; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.context.Scope; +import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; + +/** + * Wrap ServerRequestHandler for tracing. + * + * @author FAWC438 + */ +public class ServerRequestHandlerTraceDelegate { + + /** + * Wrap ServerRequestHandler for tracing. + * + * @param handler ServerRequestHandler + * @return ServerRequestHandler + */ + public static ServerRequestHandler warp(ServerRequestHandler handler) { + return (request) -> { + String methodName = "requestReply"; + String moduleName = request.getModule(); + + String spanName = TraceMonitor.getNacosClientRequestFromServerSpanName() + " / " + moduleName; + SpanBuilder spanBuilder = TraceMonitor.getTracer().spanBuilder(spanName); + // SpanKind.SERVER means incoming span rather than the span in the server side. + // See https://opentelemetry.io/docs/specs/otel/trace/api/#spankind + spanBuilder.setSpanKind(SpanKind.SERVER); + spanBuilder.setAttribute(NacosSemanticAttributes.CLIENT_VERSION, VersionUtils.getFullClientVersion()); + spanBuilder.setAttribute(SemanticAttributes.CODE_NAMESPACE, handler.getClass().getName()); + spanBuilder.setAttribute(SemanticAttributes.CODE_FUNCTION, methodName); + spanBuilder.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_ID, request.getRequestId()); + spanBuilder.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_MODULE, moduleName); + + Span span = spanBuilder.startSpan(); + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + if (request instanceof ConfigChangeNotifyRequest) { + ConfigChangeNotifyRequest configChangeNotifyRequest = (ConfigChangeNotifyRequest) request; + span.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_ID, + configChangeNotifyRequest.getRequestId()); + span.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_DATA_ID, + configChangeNotifyRequest.getDataId()); + span.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_GROUP, + configChangeNotifyRequest.getGroup()); + span.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_TENANT, + configChangeNotifyRequest.getTenant()); + span.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_TYPE, + ConfigChangeNotifyRequest.class.getSimpleName()); + + } else if (request instanceof ClientConfigMetricRequest) { + span.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_TYPE, + ClientConfigMetricRequest.class.getSimpleName()); + + } else if (request instanceof NotifySubscriberRequest) { + NotifySubscriberRequest notifySubscriberRequest = (NotifySubscriberRequest) request; + span.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_NAMESPACE, + notifySubscriberRequest.getNamespace()); + span.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_SERVICE_NAME, + notifySubscriberRequest.getServiceName()); + if (notifySubscriberRequest.getServiceInfo() != null) { + span.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_GROUP, + notifySubscriberRequest.getServiceInfo().getGroupName()); + span.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_SERVICE_CLUSTER_NAME, + notifySubscriberRequest.getServiceInfo().getClusters()); + } + span.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_TYPE, + NotifySubscriberRequest.class.getSimpleName()); + + } + // More request type can be added here. + } + + return handler.requestReply(request); + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + + }; + } +} diff --git a/client/src/main/java/com/alibaba/nacos/client/config/proxy/ClientWorkerProxy.java b/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ClientWorkerProxy.java similarity index 98% rename from client/src/main/java/com/alibaba/nacos/client/config/proxy/ClientWorkerProxy.java rename to client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ClientWorkerProxy.java index cb5f6e397e7..a0b59499259 100644 --- a/client/src/main/java/com/alibaba/nacos/client/config/proxy/ClientWorkerProxy.java +++ b/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ClientWorkerProxy.java @@ -16,7 +16,7 @@ * */ -package com.alibaba.nacos.client.config.proxy; +package com.alibaba.nacos.client.monitor.delegate.config; import com.alibaba.nacos.api.config.listener.Listener; import com.alibaba.nacos.api.exception.NacosException; diff --git a/client/src/main/java/com/alibaba/nacos/client/monitor/config/ClientWorkerTraceDelegate.java b/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ClientWorkerTraceDelegate.java similarity index 72% rename from client/src/main/java/com/alibaba/nacos/client/monitor/config/ClientWorkerTraceDelegate.java rename to client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ClientWorkerTraceDelegate.java index a83ffddfd0d..992a0d641a2 100644 --- a/client/src/main/java/com/alibaba/nacos/client/monitor/config/ClientWorkerTraceDelegate.java +++ b/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ClientWorkerTraceDelegate.java @@ -16,7 +16,7 @@ * */ -package com.alibaba.nacos.client.monitor.config; +package com.alibaba.nacos.client.monitor.delegate.config; import com.alibaba.nacos.api.config.listener.Listener; import com.alibaba.nacos.api.exception.NacosException; @@ -26,6 +26,7 @@ import com.alibaba.nacos.client.config.impl.ClientWorker; import com.alibaba.nacos.client.config.impl.ServerListManager; import com.alibaba.nacos.client.env.NacosClientProperties; +import com.alibaba.nacos.client.monitor.config.ConfigTrace; import com.alibaba.nacos.common.constant.NacosSemanticAttributes; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanBuilder; @@ -36,7 +37,7 @@ import java.util.List; /** - * Opentelemetry Trace delegate for {@link com.alibaba.nacos.client.config.proxy.ClientWorkerProxy}. + * Opentelemetry Trace delegate for {@link ClientWorker}. * * @author FAWC438 */ @@ -61,19 +62,6 @@ private SpanBuilder initServiceSpanBuilder(String methodName) { return spanBuilder; } - /** - * Init Worker level SpanBuilder with method name. - * - * @param methodName method name - * @return SpanBuilder - */ - private SpanBuilder initWorkerSpanBuilder(String methodName) { - SpanBuilder spanBuilder = ConfigTrace.getClientConfigWorkerSpanBuilder(methodName); - spanBuilder.setAttribute(SemanticAttributes.CODE_NAMESPACE, super.getClass().getName()); - spanBuilder.setAttribute(SemanticAttributes.CODE_FUNCTION, methodName); - spanBuilder.setAttribute(NacosSemanticAttributes.AGENT_NAME, super.getAgentName()); - return spanBuilder; - } /** * Add listeners for data. @@ -91,22 +79,11 @@ public void addListeners(String dataId, String group, List l span.setAttribute(NacosSemanticAttributes.GROUP, group); } - group = super.blank2defaultGroup(group); - - CacheData cache = this.addCacheDataIfAbsent(dataId, group); - - synchronized (cache) { - for (Listener listener : listeners) { - cache.addListener(listener); - } - cache.setDiscard(false); - cache.setConsistentWithServer(false); - super.agent.notifyListenConfig(); - } + super.addListeners(dataId, group, listeners); } catch (Exception e) { span.recordException(e); - span.setStatus(StatusCode.ERROR, "Add listeners failed"); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); throw e; } finally { span.end(); @@ -135,21 +112,7 @@ public void addTenantListenersWithContent(String dataId, String group, String co span.setAttribute(NacosSemanticAttributes.CONTENT, content); } - group = super.blank2defaultGroup(group); - String tenant = super.agent.getTenant(); - - CacheData cache = this.addCacheDataIfAbsent(dataId, group, tenant); - - synchronized (cache) { - cache.setEncryptedDataKey(encryptedDataKey); - cache.setContent(content); - for (Listener listener : listeners) { - cache.addListener(listener); - } - cache.setDiscard(false); - cache.setConsistentWithServer(false); - super.agent.notifyListenConfig(); - } + super.addTenantListenersWithContent(dataId, group, content, encryptedDataKey, listeners); } catch (Exception e) { span.recordException(e); @@ -179,19 +142,7 @@ public void addTenantListeners(String dataId, String group, ListFAWC438 + */ +public class ServerHttpAgentTraceDelegate extends ServerHttpAgent { + + public ServerHttpAgentTraceDelegate(ServerListManager mgr) { + super(mgr); + } + + private SpanBuilder initHttpSpanBuilder(String methodName, String httpMethod) { + SpanBuilder spanBuilder = ConfigTrace.getClientConfigHttpSpanBuilder(httpMethod); + spanBuilder.setAttribute(SemanticAttributes.CODE_NAMESPACE, super.getClass().getName()); + spanBuilder.setAttribute(SemanticAttributes.CODE_FUNCTION, methodName); + spanBuilder.setAttribute(NacosSemanticAttributes.AGENT_NAME, super.getName()); + spanBuilder.setAttribute(NacosSemanticAttributes.TENANT, super.getTenant()); + spanBuilder.setAttribute(NacosSemanticAttributes.NAMESPACE, super.getNamespace()); + spanBuilder.setAttribute(NacosSemanticAttributes.ENCODE, super.getEncode()); + return spanBuilder; + } + + @Override + public HttpRestResult httpGet(String path, Map headers, Map paramValues, + String encode, long readTimeoutMs) throws Exception { + String methodName = "httpGet"; + String httpMethod = HttpMethod.GET; + Span span = initHttpSpanBuilder(methodName, httpMethod).startSpan(); + + try (Scope ignored = span.makeCurrent()) { + if (span.isRecording()) { + // No providing span context for http request since HTTP agent will be deprecated. + span.setAttribute(SemanticAttributes.HTTP_METHOD, httpMethod); + span.setAttribute(SemanticAttributes.HTTP_URL, path); + } + + HttpRestResult restResult = super.httpGet(path, headers, paramValues, encode, readTimeoutMs); + + if (span.isRecording()) { + int resultCode = restResult.getCode(); + span.setAttribute(SemanticAttributes.HTTP_STATUS_CODE, resultCode); + + if (isFail(restResult)) { + span.setStatus(StatusCode.ERROR, "Http request failed"); + } else { + span.setStatus(StatusCode.OK, "Http request success"); + } + } + return restResult; + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + @Override + public HttpRestResult httpPost(String path, Map headers, Map paramValues, + String encode, long readTimeoutMs) throws Exception { + String methodName = "httpPost"; + String httpMethod = HttpMethod.POST; + Span span = initHttpSpanBuilder(methodName, httpMethod).startSpan(); + + try (Scope ignored = span.makeCurrent()) { + if (span.isRecording()) { + // No providing span context for http request since HTTP agent will be deprecated. + span.setAttribute(SemanticAttributes.HTTP_METHOD, httpMethod); + span.setAttribute(SemanticAttributes.HTTP_URL, path); + } + + HttpRestResult restResult = super.httpPost(path, headers, paramValues, encode, readTimeoutMs); + + if (span.isRecording()) { + int resultCode = restResult.getCode(); + span.setAttribute(SemanticAttributes.HTTP_STATUS_CODE, resultCode); + + if (isFail(restResult)) { + span.setStatus(StatusCode.ERROR, "Http request failed"); + } else { + span.setStatus(StatusCode.OK, "Http request success"); + } + } + return restResult; + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + @Override + public HttpRestResult httpDelete(String path, Map headers, Map paramValues, + String encode, long readTimeoutMs) throws Exception { + String methodName = "httpDelete"; + String httpMethod = HttpMethod.DELETE; + Span span = initHttpSpanBuilder(methodName, httpMethod).startSpan(); + + try (Scope ignored = span.makeCurrent()) { + if (span.isRecording()) { + // No providing span context for http request since HTTP agent will be deprecated. + span.setAttribute(SemanticAttributes.HTTP_METHOD, httpMethod); + span.setAttribute(SemanticAttributes.HTTP_URL, path); + } + + HttpRestResult restResult = super.httpDelete(path, headers, paramValues, encode, readTimeoutMs); + + if (span.isRecording()) { + int resultCode = restResult.getCode(); + span.setAttribute(SemanticAttributes.HTTP_STATUS_CODE, resultCode); + + if (isFail(restResult)) { + span.setStatus(StatusCode.ERROR, "Http request failed"); + } else { + span.setStatus(StatusCode.OK, "Http request success"); + } + } + return restResult; + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } +} diff --git a/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/naming/NamingClientProxyTraceDelegate.java b/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/naming/NamingClientProxyTraceDelegate.java new file mode 100644 index 00000000000..8feb1014679 --- /dev/null +++ b/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/naming/NamingClientProxyTraceDelegate.java @@ -0,0 +1,594 @@ +/* + * + * Copyright 1999-2023 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.client.monitor.delegate.naming; + +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.naming.pojo.Instance; +import com.alibaba.nacos.api.naming.pojo.ListView; +import com.alibaba.nacos.api.naming.pojo.Service; +import com.alibaba.nacos.api.naming.pojo.ServiceInfo; +import com.alibaba.nacos.api.selector.AbstractSelector; +import com.alibaba.nacos.client.monitor.naming.NamingTrace; +import com.alibaba.nacos.client.naming.remote.NamingClientProxy; +import com.alibaba.nacos.client.naming.remote.gprc.NamingGrpcClientProxy; +import com.alibaba.nacos.client.naming.remote.http.NamingHttpClientProxy; +import com.alibaba.nacos.common.constant.NacosSemanticAttributes; +import com.alibaba.nacos.common.utils.HttpMethod; +import com.alibaba.nacos.common.utils.StringUtils; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanBuilder; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.context.Scope; +import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; + +import java.util.List; + +/** + * Opentelemetry Trace delegate for {@link NamingClientProxy}. + * + * @author FAWC438 + */ +public class NamingClientProxyTraceDelegate implements NamingClientProxy { + + private final NamingClientProxy namingClientProxyImpl; + + private final String namingClientType; + + /** + * Constructor with a naming client proxy. This class will delegate all method for Opentelemetry trace. + * + * @param namingClientProxyImpl naming client proxy + */ + public NamingClientProxyTraceDelegate(NamingClientProxy namingClientProxyImpl) { + this.namingClientProxyImpl = namingClientProxyImpl; + + if (this.namingClientProxyImpl instanceof NamingGrpcClientProxy) { + this.namingClientType = "grpc"; + } else if (this.namingClientProxyImpl instanceof NamingHttpClientProxy) { + this.namingClientType = "http"; + } else { + this.namingClientType = "delegate"; + } + } + + /** + * Init SpanBuilder with method name. + * + * @param methodName method name + * @return SpanBuilder + */ + private SpanBuilder initSpanBuilder(String methodName) { + SpanBuilder spanBuilder; + if (namingClientType.equals("grpc") || namingClientType.equals("http")) { + spanBuilder = NamingTrace.getClientNamingWorkerSpanBuilder(methodName); + } else { + spanBuilder = NamingTrace.getClientNamingServiceSpanBuilder(methodName); + } + + spanBuilder.setAttribute(SemanticAttributes.CODE_NAMESPACE, namingClientProxyImpl.getClass().getName()); + spanBuilder.setAttribute(SemanticAttributes.CODE_FUNCTION, methodName); + spanBuilder.setAttribute(NacosSemanticAttributes.NAMESPACE, namingClientProxyImpl.getNamespace()); + spanBuilder.setAttribute(NacosSemanticAttributes.NAMING_CLIENT_TYPE, namingClientType); + + return spanBuilder; + } + + /** + * Register an instance to service with specified instance properties. + * + * @param serviceName name of service + * @param groupName group of service + * @param instance instance to register + * @throws NacosException nacos exception + */ + @Override + public void registerService(String serviceName, String groupName, Instance instance) throws NacosException { + Span span = initSpanBuilder("registerService").startSpan(); + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, serviceName); + span.setAttribute(NacosSemanticAttributes.GROUP, groupName); + span.setAttribute(NacosSemanticAttributes.INSTANCE, instance.toString()); + } + + namingClientProxyImpl.registerService(serviceName, groupName, instance); + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Batch register instance to service with specified instance properties. + * + * @param serviceName service name + * @param groupName group name + * @param instances instance + * @throws NacosException nacos exception + * @since 2.1.1 + */ + @Override + public void batchRegisterService(String serviceName, String groupName, List instances) + throws NacosException { + Span span = initSpanBuilder("batchRegisterService").startSpan(); + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, serviceName); + span.setAttribute(NacosSemanticAttributes.GROUP, groupName); + span.setAttribute(NacosSemanticAttributes.INSTANCE, StringUtils.join(instances, ", ")); + } + + namingClientProxyImpl.batchRegisterService(serviceName, groupName, instances); + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Batch deRegister instance to service with specified instance properties. + * + * @param serviceName service name + * @param groupName group name + * @param instances deRegister instance + * @throws NacosException nacos exception + * @since 2.2.0 + */ + @Override + public void batchDeregisterService(String serviceName, String groupName, List instances) + throws NacosException { + Span span = initSpanBuilder("batchDeregisterService").startSpan(); + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, serviceName); + span.setAttribute(NacosSemanticAttributes.GROUP, groupName); + span.setAttribute(NacosSemanticAttributes.INSTANCE, StringUtils.join(instances, ", ")); + } + + namingClientProxyImpl.batchDeregisterService(serviceName, groupName, instances); + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Deregister instance from a service. + * + * @param serviceName name of service + * @param groupName group name + * @param instance instance + * @throws NacosException nacos exception + */ + @Override + public void deregisterService(String serviceName, String groupName, Instance instance) throws NacosException { + Span span = initSpanBuilder("deregisterService").startSpan(); + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, serviceName); + span.setAttribute(NacosSemanticAttributes.GROUP, groupName); + span.setAttribute(NacosSemanticAttributes.INSTANCE, instance.toString()); + } + + namingClientProxyImpl.deregisterService(serviceName, groupName, instance); + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Update instance to service. + * + * @param serviceName service name + * @param groupName group name + * @param instance instance + * @throws NacosException nacos exception + */ + @Override + public void updateInstance(String serviceName, String groupName, Instance instance) throws NacosException { + Span span = initSpanBuilder("updateInstance").startSpan(); + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(SemanticAttributes.HTTP_METHOD, HttpMethod.PUT); + span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, serviceName); + span.setAttribute(NacosSemanticAttributes.GROUP, groupName); + span.setAttribute(NacosSemanticAttributes.INSTANCE, instance.toString()); + } + + namingClientProxyImpl.updateInstance(serviceName, groupName, instance); + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Query instance list. + * + * @param serviceName service name + * @param groupName group name + * @param clusters clusters + * @param udpPort udp port + * @param healthyOnly healthy only + * @return service info + * @throws NacosException nacos exception + */ + @Override + public ServiceInfo queryInstancesOfService(String serviceName, String groupName, String clusters, int udpPort, + boolean healthyOnly) throws NacosException { + Span span = initSpanBuilder("queryInstancesOfService").startSpan(); + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, serviceName); + span.setAttribute(NacosSemanticAttributes.GROUP, groupName); + span.setAttribute(NacosSemanticAttributes.CLUSTER, clusters); + span.setAttribute(NacosSemanticAttributes.UDP_PORT, udpPort); + span.setAttribute(NacosSemanticAttributes.HEALTHY_ONLY, healthyOnly); + } + + ServiceInfo serviceInfo = namingClientProxyImpl.queryInstancesOfService(serviceName, groupName, clusters, + udpPort, healthyOnly); + + if (span.isRecording() && serviceInfo != null) { + span.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_RESULT, + StringUtils.join(serviceInfo.getHosts(), ", ")); + } + return serviceInfo; + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Query Service. + * + * @param serviceName service name + * @param groupName group name + * @return service + * @throws NacosException nacos exception + */ + @Override + public Service queryService(String serviceName, String groupName) throws NacosException { + Span span = initSpanBuilder("queryService").startSpan(); + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(SemanticAttributes.HTTP_METHOD, HttpMethod.GET); + span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, serviceName); + span.setAttribute(NacosSemanticAttributes.GROUP, groupName); + } + + return namingClientProxyImpl.queryService(serviceName, groupName); + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Create service. + * + * @param service service + * @param selector selector + * @throws NacosException nacos exception + */ + @Override + public void createService(Service service, AbstractSelector selector) throws NacosException { + Span span = initSpanBuilder("createService").startSpan(); + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(SemanticAttributes.HTTP_METHOD, HttpMethod.POST); + span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, service.getName()); + span.setAttribute(NacosSemanticAttributes.GROUP, service.getGroupName()); + } + + namingClientProxyImpl.createService(service, selector); + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Delete service. + * + * @param serviceName service name + * @param groupName group name + * @return true if delete ok + * @throws NacosException nacos exception + */ + @Override + public boolean deleteService(String serviceName, String groupName) throws NacosException { + Span span = initSpanBuilder("deleteService").startSpan(); + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(SemanticAttributes.HTTP_METHOD, HttpMethod.DELETE); + span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, serviceName); + span.setAttribute(NacosSemanticAttributes.GROUP, groupName); + } + + return namingClientProxyImpl.deleteService(serviceName, groupName); + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Update service. + * + * @param service service + * @param selector selector + * @throws NacosException nacos exception + */ + @Override + public void updateService(Service service, AbstractSelector selector) throws NacosException { + Span span = initSpanBuilder("updateService").startSpan(); + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(SemanticAttributes.HTTP_METHOD, HttpMethod.PUT); + span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, service.getName()); + span.setAttribute(NacosSemanticAttributes.GROUP, service.getGroupName()); + } + + namingClientProxyImpl.updateService(service, selector); + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Get service list. + * + * @param pageNo page number + * @param pageSize size per page + * @param groupName group name of service + * @param selector selector + * @return list of service + * @throws NacosException nacos exception + */ + @Override + public ListView getServiceList(int pageNo, int pageSize, String groupName, AbstractSelector selector) + throws NacosException { + Span span = initSpanBuilder("getServiceList").startSpan(); + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + if (namingClientType.equals("grpc")) { + span.setAttribute(SemanticAttributes.RPC_SYSTEM, "grpc"); + } else if (namingClientType.equals("http")) { + span.setAttribute(SemanticAttributes.HTTP_METHOD, HttpMethod.GET); + } + span.setAttribute(NacosSemanticAttributes.PAGE_NO, pageNo); + span.setAttribute(NacosSemanticAttributes.PAGE_SIZE, pageSize); + span.setAttribute(NacosSemanticAttributes.GROUP, groupName); + } + + ListView serviceList = namingClientProxyImpl.getServiceList(pageNo, pageSize, groupName, selector); + + if (span.isRecording() && serviceList != null) { + span.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_RESULT, + StringUtils.join(serviceList.getData(), ", ")); + } + return serviceList; + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Subscribe service. + * + * @param serviceName service name + * @param groupName group name + * @param clusters clusters, current only support subscribe all clusters, maybe deprecated + * @return current service info of subscribe service + * @throws NacosException nacos exception + */ + @Override + public ServiceInfo subscribe(String serviceName, String groupName, String clusters) throws NacosException { + Span span = initSpanBuilder("subscribe").startSpan(); + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, serviceName); + span.setAttribute(NacosSemanticAttributes.GROUP, groupName); + span.setAttribute(NacosSemanticAttributes.CLUSTER, clusters); + } + + return namingClientProxyImpl.subscribe(serviceName, groupName, clusters); + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Unsubscribe service. + * + * @param serviceName service name + * @param groupName group name + * @param clusters clusters, current only support subscribe all clusters, maybe deprecated + * @throws NacosException nacos exception + */ + @Override + public void unsubscribe(String serviceName, String groupName, String clusters) throws NacosException { + Span span = initSpanBuilder("unsubscribe").startSpan(); + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, serviceName); + span.setAttribute(NacosSemanticAttributes.GROUP, groupName); + span.setAttribute(NacosSemanticAttributes.CLUSTER, clusters); + } + + namingClientProxyImpl.unsubscribe(serviceName, groupName, clusters); + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Judge whether service has been subscribed. + * + * @param serviceName service name + * @param groupName group name + * @param clusters clusters, current only support subscribe all clusters, maybe deprecated + * @return {@code true} if subscribed, otherwise {@code false} + * @throws NacosException nacos exception + */ + @Override + public boolean isSubscribed(String serviceName, String groupName, String clusters) throws NacosException { + Span span = initSpanBuilder("isSubscribed").startSpan(); + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, serviceName); + span.setAttribute(NacosSemanticAttributes.GROUP, groupName); + span.setAttribute(NacosSemanticAttributes.CLUSTER, clusters); + } + + return namingClientProxyImpl.isSubscribed(serviceName, groupName, clusters); + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Check Server healthy. + * + * @return true if server is healthy + */ + @Override + public boolean serverHealthy() { + Span span = initSpanBuilder("serverHealthy").startSpan(); + try (Scope ignored = span.makeCurrent()) { + + boolean isHealthy = namingClientProxyImpl.serverHealthy(); + + if (span.isRecording()) { + if (isHealthy) { + span.setStatus(StatusCode.OK, "Server is up"); + } else { + span.setStatus(StatusCode.ERROR, "Server is down"); + } + } + + return isHealthy; + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Get namespace of naming client. + * + * @return namespace + */ + @Override + public String getNamespace() { + return namingClientProxyImpl.getNamespace(); + } + + /** + * Shutdown the Resources, such as Thread Pool. + * + * @throws NacosException exception. + */ + @Override + public void shutdown() throws NacosException { + namingClientProxyImpl.shutdown(); + } +} diff --git a/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/naming/NamingGrpcRedoServiceTraceDelegate.java b/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/naming/NamingGrpcRedoServiceTraceDelegate.java new file mode 100644 index 00000000000..71978cdea98 --- /dev/null +++ b/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/naming/NamingGrpcRedoServiceTraceDelegate.java @@ -0,0 +1,376 @@ +/* + * + * Copyright 1999-2023 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.client.monitor.delegate.naming; + +import com.alibaba.nacos.api.naming.pojo.Instance; +import com.alibaba.nacos.client.monitor.naming.NamingTrace; +import com.alibaba.nacos.client.naming.remote.gprc.NamingGrpcClientProxy; +import com.alibaba.nacos.client.naming.remote.gprc.redo.NamingGrpcRedoService; +import com.alibaba.nacos.client.naming.remote.gprc.redo.data.InstanceRedoData; +import com.alibaba.nacos.common.constant.NacosSemanticAttributes; +import com.alibaba.nacos.common.utils.StringUtils; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanBuilder; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.context.Scope; +import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; + +import java.util.List; + +/** + * Opentelemetry Trace delegate for {@link NamingGrpcRedoService}. + * + * @author FAWC438 + */ +public class NamingGrpcRedoServiceTraceDelegate extends NamingGrpcRedoService { + + public NamingGrpcRedoServiceTraceDelegate(NamingGrpcClientProxy clientProxy) { + super(clientProxy); + } + + /** + * Init SpanBuilder with method name. + * + * @param methodName method name + * @return SpanBuilder + */ + private SpanBuilder initSpanBuilder(String methodName) { + SpanBuilder spanBuilder = NamingTrace.getClientNamingWorkerSpanBuilder(methodName); + spanBuilder.setAttribute(SemanticAttributes.CODE_NAMESPACE, super.getClass().getName()); + spanBuilder.setAttribute(SemanticAttributes.CODE_FUNCTION, methodName); + spanBuilder.setAttribute(NacosSemanticAttributes.NAMESPACE, super.getNamespace()); + return spanBuilder; + } + + /** + * Cache registered instance for redo. + * + * @param serviceName service name + * @param groupName group name + * @param instance registered instance + */ + @Override + public void cacheInstanceForRedo(String serviceName, String groupName, Instance instance) { + Span span = initSpanBuilder("cacheInstanceForRedo").startSpan(); + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, serviceName); + span.setAttribute(NacosSemanticAttributes.GROUP, groupName); + span.setAttribute(NacosSemanticAttributes.INSTANCE, instance.toString()); + } + + super.cacheInstanceForRedo(serviceName, groupName, instance); + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Cache registered instances for redo. + * + * @param serviceName service name + * @param groupName group name + * @param instances batch registered instance + */ + @Override + public void cacheInstanceForRedo(String serviceName, String groupName, List instances) { + Span span = initSpanBuilder("cacheInstanceForRedo").startSpan(); + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, serviceName); + span.setAttribute(NacosSemanticAttributes.GROUP, groupName); + span.setAttribute(NacosSemanticAttributes.INSTANCE, StringUtils.join(instances, ", ")); + } + + super.cacheInstanceForRedo(serviceName, groupName, instances); + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Instance register successfully, mark registered status as {@code true}. + * + * @param serviceName service name + * @param groupName group name + */ + @Override + public void instanceRegistered(String serviceName, String groupName) { + Span span = initSpanBuilder("instanceRegistered").startSpan(); + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, serviceName); + span.setAttribute(NacosSemanticAttributes.GROUP, groupName); + } + + super.instanceRegistered(serviceName, groupName); + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Instance deregister, mark unregistering status as {@code true}. + * + * @param serviceName service name + * @param groupName group name + */ + @Override + public void instanceDeregister(String serviceName, String groupName) { + Span span = initSpanBuilder("instanceDeregister").startSpan(); + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, serviceName); + span.setAttribute(NacosSemanticAttributes.GROUP, groupName); + } + + super.instanceDeregister(serviceName, groupName); + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Instance deregister finished, mark unregistered status. + * + * @param serviceName service name + * @param groupName group name + */ + @Override + public void instanceDeregistered(String serviceName, String groupName) { + Span span = initSpanBuilder("instanceDeregistered").startSpan(); + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, serviceName); + span.setAttribute(NacosSemanticAttributes.GROUP, groupName); + } + + super.instanceDeregistered(serviceName, groupName); + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Cache subscriber for redo. + * + * @param serviceName service name + * @param groupName group name + * @param cluster cluster + */ + @Override + public void cacheSubscriberForRedo(String serviceName, String groupName, String cluster) { + Span span = initSpanBuilder("cacheSubscriberForRedo").startSpan(); + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, serviceName); + span.setAttribute(NacosSemanticAttributes.GROUP, groupName); + span.setAttribute(NacosSemanticAttributes.CLUSTER, cluster); + } + + super.cacheSubscriberForRedo(serviceName, groupName, cluster); + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Subscriber register successfully, mark registered status as {@code true}. + * + * @param serviceName service name + * @param groupName group name + * @param cluster cluster + */ + @Override + public void subscriberRegistered(String serviceName, String groupName, String cluster) { + Span span = initSpanBuilder("subscriberRegistered").startSpan(); + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, serviceName); + span.setAttribute(NacosSemanticAttributes.GROUP, groupName); + span.setAttribute(NacosSemanticAttributes.CLUSTER, cluster); + } + + super.subscriberRegistered(serviceName, groupName, cluster); + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Subscriber deregister, mark unregistering status as {@code true}. + * + * @param serviceName service name + * @param groupName group name + * @param cluster cluster + */ + @Override + public void subscriberDeregister(String serviceName, String groupName, String cluster) { + Span span = initSpanBuilder("subscriberDeregister").startSpan(); + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, serviceName); + span.setAttribute(NacosSemanticAttributes.GROUP, groupName); + span.setAttribute(NacosSemanticAttributes.CLUSTER, cluster); + } + + super.subscriberDeregister(serviceName, groupName, cluster); + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Judge subscriber has registered to server. + * + * @param serviceName service name + * @param groupName group name + * @param cluster cluster + * @return {@code true} if subscribed, otherwise {@code false} + */ + @Override + public boolean isSubscriberRegistered(String serviceName, String groupName, String cluster) { + Span span = initSpanBuilder("isSubscriberRegistered").startSpan(); + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, serviceName); + span.setAttribute(NacosSemanticAttributes.GROUP, groupName); + span.setAttribute(NacosSemanticAttributes.CLUSTER, cluster); + } + + return super.isSubscriberRegistered(serviceName, groupName, cluster); + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + + /** + * Remove subscriber for redo. + * + * @param serviceName service name + * @param groupName group name + * @param cluster cluster + */ + @Override + public void removeSubscriberForRedo(String serviceName, String groupName, String cluster) { + Span span = initSpanBuilder("removeSubscriberForRedo").startSpan(); + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, serviceName); + span.setAttribute(NacosSemanticAttributes.GROUP, groupName); + span.setAttribute(NacosSemanticAttributes.CLUSTER, cluster); + } + + super.removeSubscriberForRedo(serviceName, groupName, cluster); + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw new RuntimeException(e); + } finally { + span.end(); + } + } + + /** + * get Cache service. + * + * @return cache service + */ + @Override + public InstanceRedoData getRegisteredInstancesByKey(String combinedServiceName) { + Span span = initSpanBuilder("getRegisteredInstancesByKey").startSpan(); + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, combinedServiceName); + } + + InstanceRedoData instanceRedoData = super.getRegisteredInstancesByKey(combinedServiceName); + + if (span.isRecording() && instanceRedoData != null) { + span.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_RESULT, + instanceRedoData.get().toString()); + } + return instanceRedoData; + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw new RuntimeException(e); + } finally { + span.end(); + } + } +} diff --git a/client/src/main/java/com/alibaba/nacos/client/naming/NacosNamingService.java b/client/src/main/java/com/alibaba/nacos/client/naming/NacosNamingService.java index 0ed3f274abe..69bc3d8bc74 100644 --- a/client/src/main/java/com/alibaba/nacos/client/naming/NacosNamingService.java +++ b/client/src/main/java/com/alibaba/nacos/client/naming/NacosNamingService.java @@ -27,7 +27,7 @@ import com.alibaba.nacos.api.naming.utils.NamingUtils; import com.alibaba.nacos.api.selector.AbstractSelector; import com.alibaba.nacos.client.env.NacosClientProperties; -import com.alibaba.nacos.client.monitor.TraceDynamicProxy; +import com.alibaba.nacos.client.monitor.delegate.naming.NamingClientProxyTraceDelegate; import com.alibaba.nacos.client.naming.cache.ServiceInfoHolder; import com.alibaba.nacos.client.naming.core.Balancer; import com.alibaba.nacos.client.naming.event.InstancesChangeEvent; @@ -100,7 +100,7 @@ private void init(Properties properties) throws NacosException { NotifyCenter.registerToPublisher(InstancesChangeEvent.class, 16384); NotifyCenter.registerSubscriber(changeNotifier); this.serviceInfoHolder = new ServiceInfoHolder(namespace, this.notifierEventScope, nacosClientProperties); - this.clientProxy = TraceDynamicProxy.getNamingClientProxyTraceProxy( + this.clientProxy = new NamingClientProxyTraceDelegate( new NamingClientProxyDelegate(this.namespace, serviceInfoHolder, nacosClientProperties, changeNotifier)); } diff --git a/client/src/main/java/com/alibaba/nacos/client/naming/remote/NamingClientProxyDelegate.java b/client/src/main/java/com/alibaba/nacos/client/naming/remote/NamingClientProxyDelegate.java index adc38e5cbbc..9df5cbaecf0 100644 --- a/client/src/main/java/com/alibaba/nacos/client/naming/remote/NamingClientProxyDelegate.java +++ b/client/src/main/java/com/alibaba/nacos/client/naming/remote/NamingClientProxyDelegate.java @@ -24,7 +24,7 @@ import com.alibaba.nacos.api.naming.utils.NamingUtils; import com.alibaba.nacos.api.selector.AbstractSelector; import com.alibaba.nacos.client.env.NacosClientProperties; -import com.alibaba.nacos.client.monitor.TraceDynamicProxy; +import com.alibaba.nacos.client.monitor.delegate.naming.NamingClientProxyTraceDelegate; import com.alibaba.nacos.client.monitor.naming.NamingMetrics; import com.alibaba.nacos.client.naming.cache.ServiceInfoHolder; import com.alibaba.nacos.client.naming.core.ServerListManager; @@ -81,9 +81,9 @@ public NamingClientProxyDelegate(String namespace, ServiceInfoHolder serviceInfo this.securityProxy = new SecurityProxy(this.serverListManager.getServerList(), NamingHttpClientManager.getInstance().getNacosRestTemplate()); initSecurityProxy(properties); - this.httpClientProxy = TraceDynamicProxy.getNamingClientProxyTraceProxy( + this.httpClientProxy = new NamingClientProxyTraceDelegate( new NamingHttpClientProxy(namespace, securityProxy, serverListManager, properties)); - this.grpcClientProxy = TraceDynamicProxy.getNamingClientProxyTraceProxy( + this.grpcClientProxy = new NamingClientProxyTraceDelegate( new NamingGrpcClientProxy(namespace, securityProxy, serverListManager, properties, serviceInfoHolder)); } diff --git a/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/NamingGrpcClientProxy.java b/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/NamingGrpcClientProxy.java index eb1d52ffa3d..a26addc9ae4 100644 --- a/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/NamingGrpcClientProxy.java +++ b/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/NamingGrpcClientProxy.java @@ -41,9 +41,9 @@ import com.alibaba.nacos.api.selector.AbstractSelector; import com.alibaba.nacos.api.selector.SelectorType; import com.alibaba.nacos.client.env.NacosClientProperties; -import com.alibaba.nacos.client.monitor.TraceDynamicProxy; import com.alibaba.nacos.client.monitor.TraceMonitor; -import com.alibaba.nacos.client.monitor.naming.NamingGrpcRedoServiceTraceProxy; +import com.alibaba.nacos.client.monitor.delegate.ServerRequestHandlerTraceDelegate; +import com.alibaba.nacos.client.monitor.delegate.naming.NamingGrpcRedoServiceTraceDelegate; import com.alibaba.nacos.client.monitor.naming.NamingMetrics; import com.alibaba.nacos.client.monitor.naming.NamingTrace; import com.alibaba.nacos.client.naming.cache.ServiceInfoHolder; @@ -95,9 +95,7 @@ public class NamingGrpcClientProxy extends AbstractNamingClientProxy { private final RpcClient rpcClient; - private final NamingGrpcRedoService redoServiceInstance; - - private final NamingGrpcRedoServiceTraceProxy redoService; + private final NamingGrpcRedoService redoService; public NamingGrpcClientProxy(String namespaceId, SecurityProxy securityProxy, ServerListFactory serverListFactory, NacosClientProperties properties, ServiceInfoHolder serviceInfoHolder) throws NacosException { @@ -111,17 +109,16 @@ public NamingGrpcClientProxy(String namespaceId, SecurityProxy securityProxy, Se labels.put(Constants.APPNAME, AppNameUtils.getAppName()); this.rpcClient = RpcClientFactory.createClient(uuid, ConnectionType.GRPC, labels, RpcClientTlsConfig.properties(properties.asProperties())); - this.redoServiceInstance = new NamingGrpcRedoService(this); - this.redoService = TraceDynamicProxy.getNamingGrpcRedoServiceTraceProxy(this.redoServiceInstance); + this.redoService = new NamingGrpcRedoServiceTraceDelegate(this); NAMING_LOGGER.info("Create naming rpc client for uuid->{}", uuid); start(serverListFactory, serviceInfoHolder); } private void start(ServerListFactory serverListFactory, ServiceInfoHolder serviceInfoHolder) throws NacosException { rpcClient.serverListFactory(serverListFactory); - rpcClient.registerConnectionListener(redoServiceInstance); + rpcClient.registerConnectionListener(redoService); rpcClient.registerServerRequestHandler( - TraceDynamicProxy.getServerRequestHandlerTraceProxy(new NamingPushRequestHandler(serviceInfoHolder))); + ServerRequestHandlerTraceDelegate.warp(new NamingPushRequestHandler(serviceInfoHolder))); rpcClient.start(); NotifyCenter.registerSubscriber(this); } diff --git a/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/redo/NamingGrpcRedoService.java b/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/redo/NamingGrpcRedoService.java index 035b9a2a3e9..3be6df96ed7 100644 --- a/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/redo/NamingGrpcRedoService.java +++ b/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/redo/NamingGrpcRedoService.java @@ -19,7 +19,6 @@ import com.alibaba.nacos.api.naming.pojo.Instance; import com.alibaba.nacos.api.naming.pojo.ServiceInfo; import com.alibaba.nacos.api.naming.utils.NamingUtils; -import com.alibaba.nacos.client.monitor.naming.NamingGrpcRedoServiceTraceProxy; import com.alibaba.nacos.client.monitor.naming.NamingMetrics; import com.alibaba.nacos.client.naming.remote.gprc.NamingGrpcClientProxy; import com.alibaba.nacos.client.naming.remote.gprc.redo.data.BatchInstanceRedoData; @@ -45,7 +44,7 @@ * * @author xiweng.yy */ -public class NamingGrpcRedoService implements ConnectionEventListener, NamingGrpcRedoServiceTraceProxy { +public class NamingGrpcRedoService implements ConnectionEventListener { private static final String REDO_THREAD_NAME = "com.alibaba.nacos.client.naming.grpc.redo"; @@ -105,7 +104,6 @@ public void onDisConnect() { * @param groupName group name * @param instance registered instance */ - @Override public void cacheInstanceForRedo(String serviceName, String groupName, Instance instance) { String key = NamingUtils.getGroupedName(serviceName, groupName); InstanceRedoData redoData = InstanceRedoData.build(serviceName, groupName, instance); @@ -121,7 +119,6 @@ public void cacheInstanceForRedo(String serviceName, String groupName, Instance * @param groupName group name * @param instances batch registered instance */ - @Override public void cacheInstanceForRedo(String serviceName, String groupName, List instances) { String key = NamingUtils.getGroupedName(serviceName, groupName); BatchInstanceRedoData redoData = BatchInstanceRedoData.build(serviceName, groupName, instances); @@ -136,7 +133,6 @@ public void cacheInstanceForRedo(String serviceName, String groupName, List findInstanceRedoData() { * @param groupName group name * @param cluster cluster */ - @Override public void cacheSubscriberForRedo(String serviceName, String groupName, String cluster) { String key = ServiceInfo.getKey(NamingUtils.getGroupedName(serviceName, groupName), cluster); SubscriberRedoData redoData = SubscriberRedoData.build(serviceName, groupName, cluster); @@ -238,7 +231,6 @@ public void cacheSubscriberForRedo(String serviceName, String groupName, String * @param groupName group name * @param cluster cluster */ - @Override public void subscriberRegistered(String serviceName, String groupName, String cluster) { String key = ServiceInfo.getKey(NamingUtils.getGroupedName(serviceName, groupName), cluster); synchronized (subscribes) { @@ -256,7 +248,6 @@ public void subscriberRegistered(String serviceName, String groupName, String cl * @param groupName group name * @param cluster cluster */ - @Override public void subscriberDeregister(String serviceName, String groupName, String cluster) { String key = ServiceInfo.getKey(NamingUtils.getGroupedName(serviceName, groupName), cluster); synchronized (subscribes) { @@ -276,7 +267,6 @@ public void subscriberDeregister(String serviceName, String groupName, String cl * @param cluster cluster * @return {@code true} if subscribed, otherwise {@code false} */ - @Override public boolean isSubscriberRegistered(String serviceName, String groupName, String cluster) { String key = ServiceInfo.getKey(NamingUtils.getGroupedName(serviceName, groupName), cluster); synchronized (subscribes) { @@ -292,7 +282,6 @@ public boolean isSubscriberRegistered(String serviceName, String groupName, Stri * @param groupName group name * @param cluster cluster */ - @Override public void removeSubscriberForRedo(String serviceName, String groupName, String cluster) { String key = ServiceInfo.getKey(NamingUtils.getGroupedName(serviceName, groupName), cluster); synchronized (subscribes) { @@ -325,12 +314,10 @@ public Set findSubscriberRedoData() { * * @return cache service */ - @Override public InstanceRedoData getRegisteredInstancesByKey(String combinedServiceName) { return registeredInstances.get(combinedServiceName); } - @Override public String getNamespace() { return this.namespace; } @@ -338,7 +325,6 @@ public String getNamespace() { /** * Shutdown redo service. */ - @Override public void shutdown() { LogUtils.NAMING_LOGGER.info("Shutdown grpc redo service executor " + redoExecutor); registeredInstances.clear(); diff --git a/client/src/test/java/com/alibaba/nacos/client/monitor/TraceDynamicProxyTest.java b/client/src/test/java/com/alibaba/nacos/client/monitor/TraceDynamicProxyTest.java index 3c89bda36fd..9df13dcc815 100644 --- a/client/src/test/java/com/alibaba/nacos/client/monitor/TraceDynamicProxyTest.java +++ b/client/src/test/java/com/alibaba/nacos/client/monitor/TraceDynamicProxyTest.java @@ -33,7 +33,7 @@ import com.alibaba.nacos.client.config.impl.ClientWorker; import com.alibaba.nacos.client.config.impl.ServerListManager; import com.alibaba.nacos.client.env.NacosClientProperties; -import com.alibaba.nacos.client.config.proxy.ClientWorkerProxy; +import com.alibaba.nacos.client.monitor.delegate.config.ClientWorkerProxy; import com.alibaba.nacos.client.monitor.naming.NamingGrpcRedoServiceTraceProxy; import com.alibaba.nacos.client.naming.cache.ServiceInfoHolder; import com.alibaba.nacos.client.naming.core.ServiceInfoUpdateService; From 539305457d43d3994cb55dbd67d047e56c36218d Mon Sep 17 00:00:00 2001 From: FAWC438 Date: Mon, 25 Dec 2023 17:38:09 +0800 Subject: [PATCH 3/5] Finish ut of ClientWorker --- .../client/config/impl/ClientWorker.java | 13 +- .../delegate/config/ClientWorkerProxy.java | 2 +- .../config/ClientWorkerTraceDelegate.java | 2 +- .../config/ConfigRpcTransportClientProxy.java | 10 +- ...gRpcTransportClientProxyTraceDelegate.java | 129 +++++---- .../delegate/OpenTelemetryBaseTest.java | 78 ++++++ ...ServerRequestHandlerTraceDelegateTest.java | 39 +++ .../config/ClientWorkerTraceDelegateTest.java | 248 ++++++++++++++++++ ...TransportClientProxyTraceDelegateTest.java | 192 ++++++++++++++ 9 files changed, 646 insertions(+), 67 deletions(-) create mode 100644 client/src/test/java/com/alibaba/nacos/client/monitor/delegate/OpenTelemetryBaseTest.java create mode 100644 client/src/test/java/com/alibaba/nacos/client/monitor/delegate/ServerRequestHandlerTraceDelegateTest.java create mode 100644 client/src/test/java/com/alibaba/nacos/client/monitor/delegate/config/ClientWorkerTraceDelegateTest.java create mode 100644 client/src/test/java/com/alibaba/nacos/client/monitor/delegate/config/ConfigRpcTransportClientProxyTraceDelegateTest.java diff --git a/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java b/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java index 0fc328cc131..006022763b0 100644 --- a/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java +++ b/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java @@ -1115,7 +1115,7 @@ public ConfigResponse queryConfig(String dataId, String group, String tenant, lo } } - ConfigQueryResponse response = (ConfigQueryResponse) agent.requestProxy(rpcClient, request, readTimeouts); + ConfigQueryResponse response = (ConfigQueryResponse) requestProxy(rpcClient, request, readTimeouts); ConfigResponse configResponse = new ConfigResponse(); if (response.isSuccess()) { @@ -1161,8 +1161,14 @@ private Response requestProxy(RpcClient rpcClientInner, Request request) throws return requestProxy(rpcClientInner, request, 3000L); } + private Response requestProxy(RpcClient rpcClientInner, Request request, long timeoutMills) + throws NacosException { + return ConfigRpcTransportClientProxyTraceDelegate.RequestProxyWarp.warp(this, rpcClientInner, request, + timeoutMills); + } + /** - * request proxy. This method is set to public for trace dynamic proxy. + * request proxy. * * @param rpcClientInner rpc client. * @param request request. @@ -1170,8 +1176,7 @@ private Response requestProxy(RpcClient rpcClientInner, Request request) throws * @throws NacosException nacos exception. */ @Override - public Response requestProxy(RpcClient rpcClientInner, Request request, long timeoutMills) - throws NacosException { + public Response rpcRequest(RpcClient rpcClientInner, Request request, long timeoutMills) throws NacosException { try { request.putAllHeader(super.getSecurityHeaders(resourceBuild(request))); request.putAllHeader(super.getCommonHeader()); diff --git a/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ClientWorkerProxy.java b/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ClientWorkerProxy.java index a0b59499259..43f6ac1c426 100644 --- a/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ClientWorkerProxy.java +++ b/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ClientWorkerProxy.java @@ -66,7 +66,7 @@ void addTenantListenersWithContent(String dataId, String group, String content, void removeTenantListener(String dataId, String group, Listener listener); /** - * Remove all listeners from config. + * Get config from server. * * @param dataId dataId * @param group group diff --git a/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ClientWorkerTraceDelegate.java b/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ClientWorkerTraceDelegate.java index 992a0d641a2..4e47632c897 100644 --- a/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ClientWorkerTraceDelegate.java +++ b/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ClientWorkerTraceDelegate.java @@ -182,7 +182,7 @@ public void removeTenantListener(String dataId, String group, Listener listener) } /** - * Remove all listeners from config. + * Get config from server. * * @param dataId dataId * @param group group diff --git a/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ConfigRpcTransportClientProxy.java b/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ConfigRpcTransportClientProxy.java index ff46d010c1a..c244a062737 100644 --- a/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ConfigRpcTransportClientProxy.java +++ b/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ConfigRpcTransportClientProxy.java @@ -29,7 +29,8 @@ import java.util.concurrent.ScheduledExecutorService; /** - * proxy interface for {@link com.alibaba.nacos.client.config.impl.ClientWorker.ConfigRpcTransportClient}. + * Since {@link com.alibaba.nacos.client.config.impl.ClientWorker.ConfigRpcTransportClient} is an anonymous inner class, + * we should make sure it implements this interface to delegate its methods for tracing. * * @author FAWC438 */ @@ -80,18 +81,15 @@ boolean publishConfig(String dataId, String group, String tenant, String appName */ boolean removeConfig(String dataId, String group, String tenant, String tag) throws NacosException; - // Methods for Rpc level config span - /** - * Request proxy. + * Rpc request. * * @param rpcClientInner rpcClientInner * @param request request * @param timeoutMills timeoutMills - * @return Response * @throws NacosException NacosException */ - Response requestProxy(RpcClient rpcClientInner, Request request, long timeoutMills) throws NacosException; + Response rpcRequest(RpcClient rpcClientInner, Request request, long timeoutMills) throws NacosException; // Other necessary methods diff --git a/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ConfigRpcTransportClientProxyTraceDelegate.java b/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ConfigRpcTransportClientProxyTraceDelegate.java index 8108101739e..7dc105880bc 100644 --- a/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ConfigRpcTransportClientProxyTraceDelegate.java +++ b/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ConfigRpcTransportClientProxyTraceDelegate.java @@ -64,21 +64,6 @@ private SpanBuilder initWorkerSpanBuilder(String methodName) { return spanBuilder; } - /** - * Init Rpc level SpanBuilder with method name. - * - * @param methodName method name - * @return SpanBuilder - */ - private SpanBuilder initRpcSpanBuilder(String methodName) { - SpanBuilder spanBuilder = ConfigTrace.getClientConfigRpcSpanBuilder(methodName); - spanBuilder.setAttribute(SemanticAttributes.CODE_NAMESPACE, - this.configRpcTransportClientImpl.getClass().getName()); - spanBuilder.setAttribute(SemanticAttributes.CODE_FUNCTION, methodName); - spanBuilder.setAttribute(NacosSemanticAttributes.AGENT_NAME, this.configRpcTransportClientImpl.getName()); - return spanBuilder; - } - /** * Query config from server. * @@ -223,55 +208,19 @@ public boolean removeConfig(String dataId, String group, String tenant, String t } /** - * Request proxy. + * Rpc request. * * @param rpcClientInner rpcClientInner * @param request request * @param timeoutMills timeoutMills - * @return Response * @throws NacosException NacosException */ @Override - public Response requestProxy(RpcClient rpcClientInner, Request request, long timeoutMills) throws NacosException { - Span span = initRpcSpanBuilder("requestProxy").startSpan(); - Response result; - try (Scope ignored = span.makeCurrent()) { - - if (span.isRecording()) { - span.setAttribute(NacosSemanticAttributes.TIMEOUT_MS, timeoutMills); - span.setAttribute(SemanticAttributes.RPC_SYSTEM, - rpcClientInner.getConnectionType().getType().toLowerCase()); - if (rpcClientInner.getCurrentServer() != null) { - span.setAttribute(NacosSemanticAttributes.SERVER_ADDRESS, - rpcClientInner.getCurrentServer().getAddress()); - } - TraceMonitor.getOpenTelemetry().getPropagators().getTextMapPropagator() - .inject(Context.current(), request.getHeaders(), TraceMonitor.getRpcContextSetter()); - } - - result = this.configRpcTransportClientImpl.requestProxy(rpcClientInner, request, timeoutMills); - - if (span.isRecording()) { - if (result == null) { - span.setStatus(StatusCode.ERROR, "Request failed: result is null"); - } else if (result.isSuccess()) { - span.setStatus(StatusCode.OK, "Request success"); - } else { - span.setStatus(StatusCode.ERROR, - "Request failed: " + result.getErrorCode() + ": " + result.getMessage()); - } - } - return result; - - } catch (Exception e) { - span.recordException(e); - span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); - throw e; - } finally { - span.end(); - } + public Response rpcRequest(RpcClient rpcClientInner, Request request, long timeoutMills) throws NacosException { + return RequestProxyWarp.warp(configRpcTransportClientImpl, rpcClientInner, request, timeoutMills); } + /** * Notify listen config. */ @@ -360,4 +309,74 @@ public boolean isHealthServer() { public void shutdown() throws NacosException { this.configRpcTransportClientImpl.shutdown(); } + + public static class RequestProxyWarp { + + private static final String METHOD_NAME = "requestProxy"; + + /** + * Init Rpc level SpanBuilder with method name. + * + * @param client rpc client + * @return SpanBuilder + */ + private static SpanBuilder initRpcSpanBuilder(ConfigRpcTransportClientProxy client, String rpcType) { + SpanBuilder spanBuilder = ConfigTrace.getClientConfigRpcSpanBuilder(rpcType); + spanBuilder.setAttribute(SemanticAttributes.CODE_NAMESPACE, client.getClass().getName()); + spanBuilder.setAttribute(SemanticAttributes.CODE_FUNCTION, METHOD_NAME); + spanBuilder.setAttribute(NacosSemanticAttributes.AGENT_NAME, client.getName()); + return spanBuilder; + } + + /** + * Warp requestProxy for tracing. + * + * @param client rpc client + * @param rpcClientInner rpcClientInner + * @param request request + * @param timeoutMills timeoutMills + * @return CacheData + */ + public static Response warp(ConfigRpcTransportClientProxy client, RpcClient rpcClientInner, Request request, + long timeoutMills) throws NacosException { + String rpcSystem = rpcClientInner.getConnectionType().getType(); + Span span = initRpcSpanBuilder(client, rpcSystem).startSpan(); + Response result; + try (Scope ignored = span.makeCurrent()) { + + if (span.isRecording()) { + span.setAttribute(NacosSemanticAttributes.TIMEOUT_MS, timeoutMills); + span.setAttribute(SemanticAttributes.RPC_SYSTEM, rpcSystem.toLowerCase()); + if (rpcClientInner.getCurrentServer() != null) { + span.setAttribute(NacosSemanticAttributes.SERVER_ADDRESS, + rpcClientInner.getCurrentServer().getAddress()); + } + TraceMonitor.getOpenTelemetry().getPropagators().getTextMapPropagator() + .inject(Context.current(), request.getHeaders(), TraceMonitor.getRpcContextSetter()); + } + + result = client.rpcRequest(rpcClientInner, request, timeoutMills); + + if (span.isRecording()) { + if (result == null) { + span.setStatus(StatusCode.ERROR, "Request failed: result is null"); + } else if (result.isSuccess()) { + span.setStatus(StatusCode.OK, "Request success"); + } else { + span.setStatus(StatusCode.ERROR, + "Request failed: " + result.getErrorCode() + ": " + result.getMessage()); + } + } + return result; + + } catch (Exception e) { + span.recordException(e); + span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName()); + throw e; + } finally { + span.end(); + } + } + } + } diff --git a/client/src/test/java/com/alibaba/nacos/client/monitor/delegate/OpenTelemetryBaseTest.java b/client/src/test/java/com/alibaba/nacos/client/monitor/delegate/OpenTelemetryBaseTest.java new file mode 100644 index 00000000000..13286fc171b --- /dev/null +++ b/client/src/test/java/com/alibaba/nacos/client/monitor/delegate/OpenTelemetryBaseTest.java @@ -0,0 +1,78 @@ +/* + * + * Copyright 1999-2023 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.client.monitor.delegate; + +import com.alibaba.nacos.client.monitor.TraceMonitor; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; +import io.opentelemetry.sdk.trace.export.SpanExporter; +import org.junit.After; +import org.junit.BeforeClass; + +import javax.annotation.ParametersAreNonnullByDefault; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +public class OpenTelemetryBaseTest { + + public static OpenTelemetry testOpenTelemetry = null; + + public static OpenTelemetryBaseTest.TestExporter testExporter = null; + + @BeforeClass + public static void init() { + testExporter = new OpenTelemetryBaseTest.TestExporter(); + testOpenTelemetry = OpenTelemetrySdk.builder().setTracerProvider( + SdkTracerProvider.builder().addSpanProcessor(SimpleSpanProcessor.create(testExporter)).build()).build(); + TraceMonitor.setOpenTelemetry(testOpenTelemetry); + } + + @After + public void clear() { + testExporter.exportedSpans.clear(); + } + + public static class TestExporter implements SpanExporter { + + public final List exportedSpans = Collections.synchronizedList(new ArrayList<>()); + + @ParametersAreNonnullByDefault + @Override + public CompletableResultCode export(Collection collection) { + exportedSpans.addAll(collection); + return CompletableResultCode.ofSuccess(); + } + + @Override + public CompletableResultCode flush() { + return CompletableResultCode.ofSuccess(); + } + + @Override + public CompletableResultCode shutdown() { + return CompletableResultCode.ofSuccess(); + } + } +} diff --git a/client/src/test/java/com/alibaba/nacos/client/monitor/delegate/ServerRequestHandlerTraceDelegateTest.java b/client/src/test/java/com/alibaba/nacos/client/monitor/delegate/ServerRequestHandlerTraceDelegateTest.java new file mode 100644 index 00000000000..a421a319faa --- /dev/null +++ b/client/src/test/java/com/alibaba/nacos/client/monitor/delegate/ServerRequestHandlerTraceDelegateTest.java @@ -0,0 +1,39 @@ +/* + * + * Copyright 1999-2023 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.client.monitor.delegate; + +import com.alibaba.nacos.api.config.remote.request.ClientConfigMetricRequest; +import com.alibaba.nacos.api.remote.request.Request; +import com.alibaba.nacos.client.monitor.TraceMonitor; +import com.alibaba.nacos.common.remote.client.ServerRequestHandler; +import org.junit.Assert; +import org.junit.Test; + +public class ServerRequestHandlerTraceDelegateTest extends OpenTelemetryBaseTest { + + @Test + public void testWarp() { + Request testRequest = new ClientConfigMetricRequest(); + ServerRequestHandler handler = ServerRequestHandlerTraceDelegate.warp((request) -> null); + Assert.assertNotNull(handler); + Assert.assertNull(handler.requestReply(testRequest)); + Assert.assertEquals(TraceMonitor.getNacosClientRequestFromServerSpanName() + " / " + testRequest.getModule(), + testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1).getName()); + } +} diff --git a/client/src/test/java/com/alibaba/nacos/client/monitor/delegate/config/ClientWorkerTraceDelegateTest.java b/client/src/test/java/com/alibaba/nacos/client/monitor/delegate/config/ClientWorkerTraceDelegateTest.java new file mode 100644 index 00000000000..aebcc767c3f --- /dev/null +++ b/client/src/test/java/com/alibaba/nacos/client/monitor/delegate/config/ClientWorkerTraceDelegateTest.java @@ -0,0 +1,248 @@ +/* + * + * Copyright 1999-2023 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.client.monitor.delegate.config; + +import com.alibaba.nacos.api.config.listener.AbstractListener; +import com.alibaba.nacos.api.config.listener.Listener; +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.client.config.filter.impl.ConfigFilterChainManager; +import com.alibaba.nacos.client.config.impl.ClientWorker; +import com.alibaba.nacos.client.config.impl.ServerListManager; +import com.alibaba.nacos.client.env.NacosClientProperties; +import com.alibaba.nacos.client.monitor.delegate.OpenTelemetryBaseTest; +import com.alibaba.nacos.common.constant.NacosSemanticAttributes; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.sdk.trace.data.SpanData; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.Properties; + +public class ClientWorkerTraceDelegateTest extends OpenTelemetryBaseTest { + + private ClientWorker clientWorker; + + @Before + public void initClientWorker() throws NacosException { + Properties prop = new Properties(); + ConfigFilterChainManager filter = new ConfigFilterChainManager(new Properties()); + ServerListManager serverListManager = Mockito.mock(ServerListManager.class); + + final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(prop); + clientWorker = new ClientWorkerTraceDelegate(filter, serverListManager, nacosClientProperties); + } + + @After + public void closeClientWorker() throws NacosException { + clientWorker.shutdown(); + } + + @Test + public void testAddListeners() throws NacosException { + Listener testListener = new AbstractListener() { + @Override + public void receiveConfigInfo(String configInfo) { + } + }; + + String dataId = "testDataId"; + String group = "testGroup"; + + clientWorker.addListeners(dataId, group, Collections.singletonList(testListener)); + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + Assert.assertEquals("Nacos.client.config.worker / addCacheDataIfAbsent", + testExporter.exportedSpans.get(0).getName()); + Assert.assertEquals("Nacos.client.config.service / addListeners", testExporter.exportedSpans.get(1).getName()); + + Assert.assertEquals(dataId, testExporter.exportedSpans.get(1).getAttributes() + .get(AttributeKey.stringKey(NacosSemanticAttributes.DATA_ID))); + Assert.assertEquals(group, testExporter.exportedSpans.get(1).getAttributes() + .get(AttributeKey.stringKey(NacosSemanticAttributes.GROUP))); + } + + @Test + public void addTenantListenersWithContent() throws NacosException { + Listener testListener = new AbstractListener() { + @Override + public void receiveConfigInfo(String configInfo) { + } + }; + + String dataId = "testDataId"; + String group = "testGroup"; + + clientWorker.addTenantListeners(dataId, group, Collections.singletonList(testListener)); + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + Assert.assertEquals("Nacos.client.config.worker / addCacheDataIfAbsent", + testExporter.exportedSpans.get(0).getName()); + Assert.assertEquals("Nacos.client.config.service / addTenantListeners", + testExporter.exportedSpans.get(1).getName()); + + Assert.assertEquals(dataId, testExporter.exportedSpans.get(1).getAttributes() + .get(AttributeKey.stringKey(NacosSemanticAttributes.DATA_ID))); + Assert.assertEquals(group, testExporter.exportedSpans.get(1).getAttributes() + .get(AttributeKey.stringKey(NacosSemanticAttributes.GROUP))); + } + + @Test + public void testAddTenantListeners() throws NacosException { + Listener testListener = new AbstractListener() { + @Override + public void receiveConfigInfo(String configInfo) { + } + }; + + String dataId = "testDataId"; + String group = "testGroup"; + + clientWorker.addTenantListeners(dataId, group, Collections.singletonList(testListener)); + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + Assert.assertEquals("Nacos.client.config.worker / addCacheDataIfAbsent", + testExporter.exportedSpans.get(0).getName()); + Assert.assertEquals("Nacos.client.config.service / addTenantListeners", + testExporter.exportedSpans.get(1).getName()); + + Assert.assertEquals(dataId, testExporter.exportedSpans.get(1).getAttributes() + .get(AttributeKey.stringKey(NacosSemanticAttributes.DATA_ID))); + Assert.assertEquals(group, testExporter.exportedSpans.get(1).getAttributes() + .get(AttributeKey.stringKey(NacosSemanticAttributes.GROUP))); + } + + @Test + public void removeTenantListener() { + Listener testListener = new AbstractListener() { + @Override + public void receiveConfigInfo(String configInfo) { + } + }; + + String dataId = "testDataId"; + String group = "testGroup"; + + clientWorker.removeTenantListener(dataId, group, testListener); + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + SpanData spanData = testExporter.exportedSpans.get(0); + Assert.assertEquals("Nacos.client.config.service / removeTenantListener", spanData.getName()); + + Assert.assertEquals(dataId, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.DATA_ID))); + Assert.assertEquals(group, spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.GROUP))); + } + + @Test + public void testGetServerConfig() { + String dataId = "a"; + String group = "b"; + String tenant = "c"; + try { + clientWorker.getServerConfig(dataId, group, tenant, 3000, false); + Assert.fail(); + } catch (NacosException e) { + Assert.assertEquals("Client not connected, current status:STARTING", e.getErrMsg()); + Assert.assertEquals(-401, e.getErrCode()); + } + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + SpanData spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1); + Assert.assertEquals("Nacos.client.config.service / getServerConfig", spanData.getName()); + + Assert.assertEquals(dataId, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.DATA_ID))); + Assert.assertEquals(group, spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.GROUP))); + Assert.assertEquals(tenant, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.TENANT))); + } + + @Test + public void testRemoveConfig() { + String dataId = "a"; + String group = "b"; + String tenant = "c"; + String tag = "tag"; + + try { + clientWorker.removeConfig(dataId, group, tenant, tag); + Assert.fail(); + } catch (NacosException e) { + Assert.assertEquals("Client not connected, current status:STARTING", e.getErrMsg()); + Assert.assertEquals(-401, e.getErrCode()); + } + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + SpanData spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1); + Assert.assertEquals("Nacos.client.config.service / removeConfig", spanData.getName()); + + Assert.assertEquals(dataId, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.DATA_ID))); + Assert.assertEquals(group, spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.GROUP))); + Assert.assertEquals(tenant, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.TENANT))); + Assert.assertEquals(tag, spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.TAG))); + } + + @Test + public void testPublishConfig() throws NacosException { + String dataId = "a"; + String group = "b"; + String tenant = "c"; + String tag = "tag"; + String content = "d"; + String appName = "app"; + String betaIps = "1.1.1.1"; + String casMd5 = "1111"; + String type = "properties"; + + boolean b = clientWorker.publishConfig(dataId, group, tenant, appName, tag, betaIps, content, null, casMd5, + type); + Assert.assertFalse(b); + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + SpanData spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1); + Assert.assertEquals("Nacos.client.config.service / publishConfig", spanData.getName()); + + Assert.assertEquals(dataId, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.DATA_ID))); + Assert.assertEquals(group, spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.GROUP))); + Assert.assertEquals(tenant, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.TENANT))); + Assert.assertEquals(tag, spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.TAG))); + Assert.assertEquals(appName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.APPLICATION_NAME))); + Assert.assertEquals(content, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.CONTENT))); + Assert.assertEquals(type, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.CONFIG_TYPE))); + } + + @Test + public void testIsHealthServer() throws NoSuchFieldException, IllegalAccessException { + ClientWorker.ConfigRpcTransportClient client = Mockito.mock(ClientWorker.ConfigRpcTransportClient.class); + Mockito.when(client.isHealthServer()).thenReturn(Boolean.TRUE); + + Field declaredField = ClientWorker.class.getDeclaredField("agent"); + declaredField.setAccessible(true); + declaredField.set(clientWorker, client); + + Assert.assertTrue(clientWorker.isHealthServer()); + Assert.assertEquals("Nacos.client.config.service / isHealthServer", + testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1).getName()); + } +} diff --git a/client/src/test/java/com/alibaba/nacos/client/monitor/delegate/config/ConfigRpcTransportClientProxyTraceDelegateTest.java b/client/src/test/java/com/alibaba/nacos/client/monitor/delegate/config/ConfigRpcTransportClientProxyTraceDelegateTest.java new file mode 100644 index 00000000000..9fd61c19611 --- /dev/null +++ b/client/src/test/java/com/alibaba/nacos/client/monitor/delegate/config/ConfigRpcTransportClientProxyTraceDelegateTest.java @@ -0,0 +1,192 @@ +/* + * + * Copyright 1999-2023 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.client.monitor.delegate.config; + +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.client.config.filter.impl.ConfigFilterChainManager; +import com.alibaba.nacos.client.config.impl.ClientWorker; +import com.alibaba.nacos.client.config.impl.ServerListManager; +import com.alibaba.nacos.client.env.NacosClientProperties; +import com.alibaba.nacos.client.monitor.delegate.OpenTelemetryBaseTest; +import com.alibaba.nacos.common.constant.NacosSemanticAttributes; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import java.util.Properties; + +public class ConfigRpcTransportClientProxyTraceDelegateTest extends OpenTelemetryBaseTest { + + // ConfigRpcTransportClient is an anonymous inner class of ClientWorker. + // So we must use ClientWorker to test ConfigRpcTransportClientProxyTraceDelegate. + + private ClientWorker clientWorker; + + @Before + public void initClientWorker() throws NacosException { + Properties prop = new Properties(); + ConfigFilterChainManager filter = new ConfigFilterChainManager(new Properties()); + ServerListManager serverListManager = Mockito.mock(ServerListManager.class); + + final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(prop); + clientWorker = new ClientWorker(filter, serverListManager, nacosClientProperties); + } + + @After + public void closeClientWorker() throws NacosException { + clientWorker.shutdown(); + } + + @Test + public void testQueryConfig() { + String dataId = "a"; + String group = "b"; + String tenant = "c"; + + try { + clientWorker.getServerConfig(dataId, group, tenant, 3000, false); + Assert.fail(); + } catch (NacosException e) { + Assert.assertEquals("Client not connected, current status:STARTING", e.getErrMsg()); + Assert.assertEquals(-401, e.getErrCode()); + } + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + SpanData spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1); + Assert.assertEquals("Nacos.client.config.worker / queryConfig", spanData.getName()); + + Assert.assertEquals(dataId, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.DATA_ID))); + Assert.assertEquals(group, spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.GROUP))); + Assert.assertEquals(tenant, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.TENANT))); + } + + @Test + public void testPublishConfig() throws NacosException { + String dataId = "a"; + String group = "b"; + String tenant = "c"; + String tag = "tag"; + String content = "d"; + String appName = "app"; + String betaIps = "1.1.1.1"; + String casMd5 = "1111"; + String type = "properties"; + + boolean b = clientWorker.publishConfig(dataId, group, tenant, appName, tag, betaIps, content, null, casMd5, + type); + Assert.assertFalse(b); + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + SpanData spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1); + Assert.assertEquals("Nacos.client.config.worker / publishConfig", spanData.getName()); + + Assert.assertEquals(dataId, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.DATA_ID))); + Assert.assertEquals(group, spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.GROUP))); + Assert.assertEquals(tenant, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.TENANT))); + Assert.assertEquals(tag, spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.TAG))); + Assert.assertEquals(appName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.APPLICATION_NAME))); + Assert.assertEquals(content, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.CONTENT))); + Assert.assertEquals(type, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.CONFIG_TYPE))); + } + + @Test + public void testRemoveConfig() throws NacosException { + String dataId = "a"; + String group = "b"; + String tenant = "c"; + String tag = "tag"; + try { + clientWorker.removeConfig(dataId, group, tenant, tag); + Assert.fail(); + } catch (NacosException e) { + Assert.assertEquals("Client not connected, current status:STARTING", e.getErrMsg()); + Assert.assertEquals(-401, e.getErrCode()); + } + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + SpanData spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1); + Assert.assertEquals("Nacos.client.config.worker / removeConfig", spanData.getName()); + + Assert.assertEquals(dataId, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.DATA_ID))); + Assert.assertEquals(group, spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.GROUP))); + Assert.assertEquals(tenant, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.TENANT))); + Assert.assertEquals(tag, spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.TAG))); + } + + @Test + public void testRequestProxy() throws NacosException { + String dataId = "a"; + String group = "b"; + String tenant = "c"; + String tag = "tag"; + String content = "d"; + String appName = "app"; + String betaIps = "1.1.1.1"; + String casMd5 = "1111"; + String type = "properties"; + + final String targetSpanName = "Nacos.client.config.rpc / GRPC"; + final String targetRpcSystem = "grpc"; + + boolean b = clientWorker.publishConfig(dataId, group, tenant, appName, tag, betaIps, content, null, casMd5, + type); + Assert.assertFalse(b); + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + SpanData spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 2); + Assert.assertEquals(targetSpanName, spanData.getName()); + Assert.assertEquals(targetRpcSystem, spanData.getAttributes().get(SemanticAttributes.RPC_SYSTEM)); + testExporter.exportedSpans.clear(); + + try { + clientWorker.getServerConfig(dataId, group, tenant, 3000, false); + Assert.fail(); + } catch (NacosException e) { + Assert.assertEquals("Client not connected, current status:STARTING", e.getErrMsg()); + Assert.assertEquals(-401, e.getErrCode()); + } + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 2); + Assert.assertEquals(targetSpanName, spanData.getName()); + Assert.assertEquals(targetRpcSystem, spanData.getAttributes().get(SemanticAttributes.RPC_SYSTEM)); + testExporter.exportedSpans.clear(); + + try { + clientWorker.removeConfig(dataId, group, tenant, tag); + Assert.fail(); + } catch (NacosException e) { + Assert.assertEquals("Client not connected, current status:STARTING", e.getErrMsg()); + Assert.assertEquals(-401, e.getErrCode()); + } + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 2); + Assert.assertEquals(targetSpanName, spanData.getName()); + Assert.assertEquals(targetRpcSystem, spanData.getAttributes().get(SemanticAttributes.RPC_SYSTEM)); + } +} From ed75140c5ee78d847ed012eb5c9a9bdb6df6af51 Mon Sep 17 00:00:00 2001 From: FAWC438 Date: Tue, 26 Dec 2023 16:19:05 +0800 Subject: [PATCH 4/5] Completed all unit tests --- .../client/config/impl/ClientWorker.java | 18 +- .../client/monitor/TraceDynamicProxy.java | 864 ------------------ .../delegate/config/ClientWorkerProxy.java | 157 ---- .../client/monitor/TraceDynamicProxyTest.java | 491 ---------- .../ServerHttpAgentTraceDelegateTest.java | 113 +++ .../NamingClientProxyTraceDelegateTest.java | 352 +++++++ ...amingGrpcRedoServiceTraceDelegateTest.java | 195 ++++ 7 files changed, 664 insertions(+), 1526 deletions(-) delete mode 100644 client/src/main/java/com/alibaba/nacos/client/monitor/TraceDynamicProxy.java delete mode 100644 client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ClientWorkerProxy.java delete mode 100644 client/src/test/java/com/alibaba/nacos/client/monitor/TraceDynamicProxyTest.java create mode 100644 client/src/test/java/com/alibaba/nacos/client/monitor/delegate/config/ServerHttpAgentTraceDelegateTest.java create mode 100644 client/src/test/java/com/alibaba/nacos/client/monitor/delegate/naming/NamingClientProxyTraceDelegateTest.java create mode 100644 client/src/test/java/com/alibaba/nacos/client/monitor/delegate/naming/NamingGrpcRedoServiceTraceDelegateTest.java diff --git a/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java b/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java index 006022763b0..f9e377a1261 100644 --- a/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java +++ b/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java @@ -44,7 +44,6 @@ import com.alibaba.nacos.client.env.NacosClientProperties; import com.alibaba.nacos.client.monitor.config.ConfigMetrics; import com.alibaba.nacos.client.monitor.delegate.ServerRequestHandlerTraceDelegate; -import com.alibaba.nacos.client.monitor.delegate.config.ClientWorkerProxy; import com.alibaba.nacos.client.monitor.delegate.config.ClientWorkerTraceDelegate; import com.alibaba.nacos.client.monitor.delegate.config.ConfigRpcTransportClientProxy; import com.alibaba.nacos.client.monitor.delegate.config.ConfigRpcTransportClientProxyTraceDelegate; @@ -104,7 +103,7 @@ * * @author Nacos */ -public class ClientWorker implements ClientWorkerProxy { +public class ClientWorker { private static final Logger LOGGER = LogUtils.logger(ClientWorker.class); @@ -179,7 +178,6 @@ public void addListeners(String dataId, String group, List l * @param listeners listeners * @throws NacosException nacos exception */ - @Override public void addTenantListeners(String dataId, String group, List listeners) throws NacosException { group = blank2defaultGroup(group); @@ -209,7 +207,6 @@ public void addTenantListeners(String dataId, String group, List listeners) throws NacosException { group = blank2defaultGroup(group); @@ -263,7 +260,6 @@ public void removeListener(String dataId, String group, Listener listener) { * @param group group of data * @param listener listener */ - @Override public void removeTenantListener(String dataId, String group, Listener listener) { group = blank2defaultGroup(group); String tenant = agent.getTenant(); @@ -307,7 +303,6 @@ void removeCache(String dataId, String group, String tenant) { * @return success or not. * @throws NacosException exception to throw. */ - @Override public boolean removeConfig(String dataId, String group, String tenant, String tag) throws NacosException { return agent.removeConfig(dataId, group, tenant, tag); } @@ -327,7 +322,6 @@ public boolean removeConfig(String dataId, String group, String tenant, String t * @return success or not. * @throws NacosException exception throw. */ - @Override public boolean publishConfig(String dataId, String group, String tenant, String appName, String tag, String betaIps, String content, String encryptedDataKey, String casMd5, String type) throws NacosException { return agent.publishConfig(dataId, group, tenant, appName, tag, betaIps, content, encryptedDataKey, casMd5, @@ -341,7 +335,6 @@ public boolean publishConfig(String dataId, String group, String tenant, String * @param group group of data * @return cache data */ - @Override public CacheData addCacheDataIfAbsent(String dataId, String group) { CacheData cache = getCache(dataId, group); @@ -386,7 +379,6 @@ public CacheData addCacheDataIfAbsent(String dataId, String group) { * @param tenant tenant of data * @return cache data */ - @Override public CacheData addCacheDataIfAbsent(String dataId, String group, String tenant) throws NacosException { CacheData cache = getCache(dataId, group, tenant); @@ -461,7 +453,6 @@ public CacheData getCache(String dataId, String group, String tenant) { return cacheMap.get().get(GroupKey.getKeyTenant(dataId, group, tenant)); } - @Override public ConfigResponse getServerConfig(String dataId, String group, String tenant, long readTimeout, boolean notify) throws NacosException { if (StringUtils.isBlank(group)) { @@ -579,7 +570,9 @@ private Map getMetricsValue( return values; } - @Override + /** + * Shutdown ClientWorker. + */ public void shutdown() throws NacosException { String className = this.getClass().getName(); LOGGER.info("{} do shutdown begin", className); @@ -595,7 +588,6 @@ public void shutdown() throws NacosException { * @return true: that means has at least one connected rpc client. false: that means does not have any connected rpc * client. */ - @Override public boolean isHealthServer() { return agent.isHealthServer(); } @@ -1305,12 +1297,10 @@ public ServerListManager getServerListManager() { } - @Override public String getAgentName() { return this.agent.getName(); } - @Override public String getAgentTenant() { return this.agent.getTenant(); } diff --git a/client/src/main/java/com/alibaba/nacos/client/monitor/TraceDynamicProxy.java b/client/src/main/java/com/alibaba/nacos/client/monitor/TraceDynamicProxy.java deleted file mode 100644 index b52435b7dfd..00000000000 --- a/client/src/main/java/com/alibaba/nacos/client/monitor/TraceDynamicProxy.java +++ /dev/null @@ -1,864 +0,0 @@ -/* - * - * Copyright 1999-2023 Alibaba Group Holding Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package com.alibaba.nacos.client.monitor; - -import com.alibaba.nacos.api.naming.pojo.Instance; -import com.alibaba.nacos.api.naming.pojo.Service; -import com.alibaba.nacos.api.naming.remote.response.QueryServiceResponse; -import com.alibaba.nacos.api.naming.remote.response.ServiceListResponse; -import com.alibaba.nacos.client.config.filter.impl.ConfigResponse; -import com.alibaba.nacos.client.config.http.HttpAgent; -import com.alibaba.nacos.client.config.impl.CacheData; -import com.alibaba.nacos.client.config.impl.ClientWorker; -import com.alibaba.nacos.client.monitor.config.ConfigTrace; -import com.alibaba.nacos.client.monitor.delegate.config.ClientWorkerProxy; -import com.alibaba.nacos.client.monitor.naming.NamingGrpcRedoServiceTraceProxy; -import com.alibaba.nacos.client.monitor.naming.NamingTrace; -import com.alibaba.nacos.client.naming.remote.NamingClientProxy; -import com.alibaba.nacos.client.naming.remote.gprc.NamingGrpcClientProxy; -import com.alibaba.nacos.client.naming.remote.gprc.redo.NamingGrpcRedoService; -import com.alibaba.nacos.client.naming.remote.gprc.redo.data.InstanceRedoData; -import com.alibaba.nacos.client.naming.remote.http.NamingHttpClientProxy; -import com.alibaba.nacos.common.constant.NacosSemanticAttributes; -import com.alibaba.nacos.common.http.HttpRestResult; -import com.alibaba.nacos.common.utils.HttpMethod; -import com.alibaba.nacos.common.utils.StringUtils; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.SpanBuilder; -import io.opentelemetry.api.trace.StatusCode; -import io.opentelemetry.context.Scope; -import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Proxy; -import java.net.HttpURLConnection; -import java.util.List; - -/** - * Utils for dynamic proxy to the OpenTelemetry tracing. - * - * @author FAWC438 - */ -public class TraceDynamicProxy { - - // Config module - - // TODO: Remove this method - public static ClientWorkerProxy getClientWorkerTraceProxy(ClientWorker clientWorker) { - return (ClientWorkerProxy) Proxy.newProxyInstance(TraceDynamicProxy.class.getClassLoader(), - new Class[] {ClientWorkerProxy.class}, (proxy, method, args) -> { - String methodName = method.getName(); - - SpanBuilder spanBuilder = ConfigTrace.getClientConfigServiceSpanBuilder(methodName); - spanBuilder.setAttribute(SemanticAttributes.CODE_NAMESPACE, clientWorker.getClass().getName()); - spanBuilder.setAttribute(SemanticAttributes.CODE_FUNCTION, methodName); - spanBuilder.setAttribute(NacosSemanticAttributes.AGENT_NAME, clientWorker.getAgentName()); - - // Service level config span - switch (methodName) { - case "addTenantListenersWithContent": { - Object result; - Span span = spanBuilder.startSpan(); - try (Scope ignored = span.makeCurrent()) { - - if (span.isRecording()) { - span.setAttribute(NacosSemanticAttributes.DATA_ID, (String) args[0]); - span.setAttribute(NacosSemanticAttributes.GROUP, (String) args[1]); - span.setAttribute(NacosSemanticAttributes.CONTENT, (String) args[2]); - } - - result = method.invoke(clientWorker, args); - - } catch (InvocationTargetException e) { - Throwable targetException = e.getTargetException(); - span.recordException(targetException); - span.setStatus(StatusCode.ERROR, targetException.getClass().getSimpleName()); - throw targetException; - } finally { - span.end(); - } - - return result; - } - case "addTenantListeners": - case "removeTenantListener": { - Object result; - Span span = spanBuilder.startSpan(); - try (Scope ignored = span.makeCurrent()) { - - if (span.isRecording()) { - span.setAttribute(NacosSemanticAttributes.DATA_ID, (String) args[0]); - span.setAttribute(NacosSemanticAttributes.GROUP, (String) args[1]); - } - - result = method.invoke(clientWorker, args); - - } catch (InvocationTargetException e) { - Throwable targetException = e.getTargetException(); - span.recordException(targetException); - span.setStatus(StatusCode.ERROR, targetException.getClass().getSimpleName()); - throw targetException; - } finally { - span.end(); - } - - return result; - } - case "getServerConfig": { - Object result; - Span span = spanBuilder.startSpan(); - try (Scope ignored = span.makeCurrent()) { - - if (span.isRecording()) { - span.setAttribute(NacosSemanticAttributes.DATA_ID, (String) args[0]); - span.setAttribute(NacosSemanticAttributes.GROUP, (String) args[1]); - span.setAttribute(NacosSemanticAttributes.TENANT, (String) args[2]); - span.setAttribute(NacosSemanticAttributes.TIMEOUT_MS, (long) args[3]); - span.setAttribute(NacosSemanticAttributes.NOTIFY, (boolean) args[4]); - } - - result = method.invoke(clientWorker, args); - - if (span.isRecording() && result != null) { - ConfigResponse configResponse = (ConfigResponse) result; - span.setAttribute(NacosSemanticAttributes.CONTENT, configResponse.getContent()); - } - - } catch (InvocationTargetException e) { - Throwable targetException = e.getTargetException(); - span.recordException(targetException); - span.setStatus(StatusCode.ERROR, targetException.getClass().getSimpleName()); - throw targetException; - } finally { - span.end(); - } - - return result; - } - case "removeConfig": { - Object result; - Span span = spanBuilder.startSpan(); - try (Scope ignored = span.makeCurrent()) { - - if (span.isRecording()) { - span.setAttribute(NacosSemanticAttributes.DATA_ID, (String) args[0]); - span.setAttribute(NacosSemanticAttributes.GROUP, (String) args[1]); - span.setAttribute(NacosSemanticAttributes.TENANT, (String) args[2]); - span.setAttribute(NacosSemanticAttributes.TAG, (String) args[3]); - } - - result = method.invoke(clientWorker, args); - - if (span.isRecording() && result != null) { - boolean removeResult = (boolean) result; - if (removeResult) { - span.setStatus(StatusCode.OK, "Remove config success"); - } else { - span.setStatus(StatusCode.ERROR, "Remove config failed"); - } - } - - } catch (InvocationTargetException e) { - Throwable targetException = e.getTargetException(); - span.recordException(targetException); - span.setStatus(StatusCode.ERROR, targetException.getClass().getSimpleName()); - throw targetException; - } finally { - span.end(); - } - - return result; - } - case "publishConfig": { - Object result; - Span span = spanBuilder.startSpan(); - try (Scope ignored = span.makeCurrent()) { - - if (span.isRecording()) { - span.setAttribute(NacosSemanticAttributes.DATA_ID, (String) args[0]); - span.setAttribute(NacosSemanticAttributes.GROUP, (String) args[1]); - span.setAttribute(NacosSemanticAttributes.TENANT, (String) args[2]); - span.setAttribute(NacosSemanticAttributes.APPLICATION_NAME, (String) args[3]); - span.setAttribute(NacosSemanticAttributes.TAG, (String) args[4]); - span.setAttribute(NacosSemanticAttributes.CONTENT, (String) args[6]); - span.setAttribute(NacosSemanticAttributes.CONFIG_TYPE, (String) args[9]); - } - - result = method.invoke(clientWorker, args); - - if (span.isRecording() && result != null) { - boolean publishResult = (boolean) result; - if (publishResult) { - span.setStatus(StatusCode.OK, "Publish config success"); - } else { - span.setStatus(StatusCode.ERROR, "Publish config failed"); - } - } - - } catch (InvocationTargetException e) { - Throwable targetException = e.getTargetException(); - span.recordException(targetException); - span.setStatus(StatusCode.ERROR, targetException.getClass().getSimpleName()); - throw targetException; - } finally { - span.end(); - } - - return result; - } - case "isHealthServer": { - Object result; - Span span = spanBuilder.startSpan(); - try (Scope ignored = span.makeCurrent()) { - - result = method.invoke(clientWorker, args); - - if (span.isRecording() && result != null) { - boolean isHealthServer = (boolean) result; - if (isHealthServer) { - span.setStatus(StatusCode.OK, "Server is up"); - } else { - span.setStatus(StatusCode.ERROR, "Server is down"); - } - } - - } catch (InvocationTargetException e) { - Throwable targetException = e.getTargetException(); - span.recordException(targetException); - span.setStatus(StatusCode.ERROR, targetException.getClass().getSimpleName()); - throw targetException; - } finally { - span.end(); - } - - return result; - } - default: - break; - } - - String targetMethodName = "addCacheDataIfAbsent"; - if (targetMethodName.equals(methodName)) { - Object result; - - spanBuilder = ConfigTrace.getClientConfigWorkerSpanBuilder(methodName); - spanBuilder.setAttribute(SemanticAttributes.CODE_NAMESPACE, clientWorker.getClass().getName()); - spanBuilder.setAttribute(SemanticAttributes.CODE_FUNCTION, methodName); - spanBuilder.setAttribute(NacosSemanticAttributes.AGENT_NAME, clientWorker.getAgentName()); - - Span span = spanBuilder.startSpan(); - try (Scope ignored = span.makeCurrent()) { - - if (span.isRecording()) { - span.setAttribute(NacosSemanticAttributes.DATA_ID, (String) args[0]); - span.setAttribute(NacosSemanticAttributes.GROUP, (String) args[1]); - String tenant = args.length > 2 ? (String) args[2] : clientWorker.getAgentTenant(); - span.setAttribute(NacosSemanticAttributes.TENANT, tenant); - } - - result = method.invoke(clientWorker, args); - - if (span.isRecording() && result instanceof CacheData) { - CacheData cacheData = (CacheData) result; - span.setAttribute(NacosSemanticAttributes.CONTENT, cacheData.getContent()); - } - - } catch (InvocationTargetException e) { - Throwable targetException = e.getTargetException(); - span.recordException(targetException); - span.setStatus(StatusCode.ERROR, targetException.getClass().getSimpleName()); - throw targetException; - } finally { - span.end(); - } - - return result; - } - - try { - return method.invoke(clientWorker, args); - } catch (InvocationTargetException e) { - throw e.getTargetException(); - } - - }); - } - - public static HttpAgent getHttpAgentTraceProxy(HttpAgent httpAgent) { - return (HttpAgent) Proxy.newProxyInstance(TraceDynamicProxy.class.getClassLoader(), - new Class[] {HttpAgent.class}, (proxy, method, args) -> { - String methodName = method.getName(); - String httpMethod; - - switch (methodName) { - case "httpGet": - httpMethod = HttpMethod.GET; - break; - case "httpPost": - httpMethod = HttpMethod.POST; - break; - case "httpDelete": - httpMethod = HttpMethod.DELETE; - break; - default: - try { - return method.invoke(httpAgent, args); - } catch (InvocationTargetException e) { - throw e.getTargetException(); - } - } - - SpanBuilder spanBuilder = ConfigTrace.getClientConfigHttpSpanBuilder(httpMethod); - spanBuilder.setAttribute(SemanticAttributes.CODE_NAMESPACE, httpAgent.getClass().getName()); - spanBuilder.setAttribute(SemanticAttributes.CODE_FUNCTION, methodName); - spanBuilder.setAttribute(NacosSemanticAttributes.AGENT_NAME, httpAgent.getName()); - spanBuilder.setAttribute(NacosSemanticAttributes.TENANT, httpAgent.getTenant()); - spanBuilder.setAttribute(NacosSemanticAttributes.NAMESPACE, httpAgent.getNamespace()); - spanBuilder.setAttribute(NacosSemanticAttributes.ENCODE, httpAgent.getEncode()); - - Object result; - Span span = spanBuilder.startSpan(); - try (Scope ignored = span.makeCurrent()) { - if (span.isRecording()) { - // No providing span context for http request since HTTP agent will be deprecated. - span.setAttribute(SemanticAttributes.HTTP_METHOD, httpMethod); - span.setAttribute(SemanticAttributes.HTTP_URL, (String) args[0]); - } - - result = method.invoke(httpAgent, args); - - if (span.isRecording() && result instanceof HttpRestResult) { - HttpRestResult restResult = (HttpRestResult) result; - int resultCode = restResult.getCode(); - span.setAttribute(SemanticAttributes.HTTP_STATUS_CODE, resultCode); - - if (isFail(resultCode)) { - span.setStatus(StatusCode.ERROR, "Http request failed"); - } else { - span.setStatus(StatusCode.OK, "Http request success"); - } - - } - } catch (InvocationTargetException e) { - Throwable targetException = e.getTargetException(); - span.recordException(targetException); - span.setStatus(StatusCode.ERROR, targetException.getClass().getSimpleName()); - throw targetException; - } finally { - span.end(); - } - return result; - - }); - } - - // Naming module - - public static NamingClientProxy getNamingClientProxyTraceProxy(NamingClientProxy namingClientProxy) { - return (NamingClientProxy) Proxy.newProxyInstance(TraceDynamicProxy.class.getClassLoader(), - new Class[] {NamingClientProxy.class}, (proxy, method, args) -> { - String methodName = method.getName(); - String namingClientType; - SpanBuilder spanBuilder; - if (namingClientProxy instanceof NamingGrpcClientProxy) { - namingClientType = "grpc"; - spanBuilder = NamingTrace.getClientNamingWorkerSpanBuilder(methodName); - } else if (namingClientProxy instanceof NamingHttpClientProxy) { - namingClientType = "http"; - spanBuilder = NamingTrace.getClientNamingWorkerSpanBuilder(methodName); - } else { - namingClientType = "Delegate"; - spanBuilder = NamingTrace.getClientNamingServiceSpanBuilder(methodName); - } - - spanBuilder.setAttribute(SemanticAttributes.CODE_NAMESPACE, namingClientProxy.getClass().getName()); - spanBuilder.setAttribute(SemanticAttributes.CODE_FUNCTION, methodName); - spanBuilder.setAttribute(NacosSemanticAttributes.NAMESPACE, namingClientProxy.getNamespace()); - spanBuilder.setAttribute(NacosSemanticAttributes.NAMING_CLIENT_TYPE, namingClientType); - - switch (methodName) { - case "registerService": - case "deregisterService": { - Object result; - Span span = spanBuilder.startSpan(); - try (Scope ignored = span.makeCurrent()) { - - if (span.isRecording()) { - span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, (String) args[0]); - span.setAttribute(NacosSemanticAttributes.GROUP, (String) args[1]); - Instance instance = (Instance) args[2]; - span.setAttribute(NacosSemanticAttributes.INSTANCE, instance.toString()); - } - - result = method.invoke(namingClientProxy, args); - - } catch (InvocationTargetException e) { - Throwable targetException = e.getTargetException(); - span.recordException(targetException); - span.setStatus(StatusCode.ERROR, targetException.getClass().getSimpleName()); - throw targetException; - } finally { - span.end(); - } - - return result; - } - case "batchRegisterService": - case "batchDeregisterService": { - Object result; - Span span = spanBuilder.startSpan(); - try (Scope ignored = span.makeCurrent()) { - - if (span.isRecording()) { - span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, (String) args[0]); - span.setAttribute(NacosSemanticAttributes.GROUP, (String) args[1]); - List instanceList = (List) args[2]; - span.setAttribute(NacosSemanticAttributes.INSTANCE, - StringUtils.join(instanceList, ", ")); - } - - result = method.invoke(namingClientProxy, args); - - } catch (InvocationTargetException e) { - Throwable targetException = e.getTargetException(); - span.recordException(targetException); - span.setStatus(StatusCode.ERROR, targetException.getClass().getSimpleName()); - throw targetException; - } finally { - span.end(); - } - - return result; - } - case "updateInstance": { - Object result; - Span span = spanBuilder.startSpan(); - try (Scope ignored = span.makeCurrent()) { - - if (span.isRecording()) { - span.setAttribute(SemanticAttributes.HTTP_METHOD, HttpMethod.PUT); - span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, (String) args[0]); - span.setAttribute(NacosSemanticAttributes.GROUP, (String) args[1]); - Instance instance = (Instance) args[2]; - span.setAttribute(NacosSemanticAttributes.INSTANCE, instance.toString()); - } - - result = method.invoke(namingClientProxy, args); - - } catch (InvocationTargetException e) { - Throwable targetException = e.getTargetException(); - span.recordException(targetException); - span.setStatus(StatusCode.ERROR, targetException.getClass().getSimpleName()); - throw targetException; - } finally { - span.end(); - } - - return result; - } - case "queryInstancesOfService": { - Object result; - Span span = spanBuilder.startSpan(); - try (Scope ignored = span.makeCurrent()) { - - if (span.isRecording()) { - span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, (String) args[0]); - span.setAttribute(NacosSemanticAttributes.GROUP, (String) args[1]); - span.setAttribute(NacosSemanticAttributes.CLUSTER, (String) args[2]); - span.setAttribute(NacosSemanticAttributes.UDP_PORT, (int) args[3]); - span.setAttribute(NacosSemanticAttributes.HEALTHY_ONLY, (boolean) args[4]); - } - - result = method.invoke(namingClientProxy, args); - - if (span.isRecording() && result != null) { - if (result instanceof QueryServiceResponse) { - QueryServiceResponse response = ((QueryServiceResponse) result); - if (response.getServiceInfo() != null) { - span.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_RESULT, - StringUtils.join(response.getServiceInfo().getHosts(), ", ")); - } - } else if (result instanceof String) { - span.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_RESULT, - (String) result); - } - } - - } catch (InvocationTargetException e) { - Throwable targetException = e.getTargetException(); - span.recordException(targetException); - span.setStatus(StatusCode.ERROR, targetException.getClass().getSimpleName()); - throw targetException; - } finally { - span.end(); - } - - return result; - } - case "queryService": { - Object result; - Span span = spanBuilder.startSpan(); - try (Scope ignored = span.makeCurrent()) { - - if (span.isRecording()) { - span.setAttribute(SemanticAttributes.HTTP_METHOD, HttpMethod.GET); - span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, (String) args[0]); - span.setAttribute(NacosSemanticAttributes.GROUP, (String) args[1]); - } - - result = method.invoke(namingClientProxy, args); - - } catch (InvocationTargetException e) { - Throwable targetException = e.getTargetException(); - span.recordException(targetException); - span.setStatus(StatusCode.ERROR, targetException.getClass().getSimpleName()); - throw targetException; - } finally { - span.end(); - } - - return result; - } - case "createService": { - Object result; - Span span = spanBuilder.startSpan(); - try (Scope ignored = span.makeCurrent()) { - - if (span.isRecording()) { - Service service = (Service) args[0]; - span.setAttribute(SemanticAttributes.HTTP_METHOD, HttpMethod.POST); - span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, service.getName()); - span.setAttribute(NacosSemanticAttributes.GROUP, service.getGroupName()); - } - - result = method.invoke(namingClientProxy, args); - - } catch (InvocationTargetException e) { - Throwable targetException = e.getTargetException(); - span.recordException(targetException); - span.setStatus(StatusCode.ERROR, targetException.getClass().getSimpleName()); - throw targetException; - } finally { - span.end(); - } - - return result; - } - case "deleteService": { - Object result; - Span span = spanBuilder.startSpan(); - try (Scope ignored = span.makeCurrent()) { - - if (span.isRecording()) { - span.setAttribute(SemanticAttributes.HTTP_METHOD, HttpMethod.DELETE); - span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, (String) args[0]); - span.setAttribute(NacosSemanticAttributes.GROUP, (String) args[1]); - } - - result = method.invoke(namingClientProxy, args); - - } catch (InvocationTargetException e) { - Throwable targetException = e.getTargetException(); - span.recordException(targetException); - span.setStatus(StatusCode.ERROR, targetException.getClass().getSimpleName()); - throw targetException; - } finally { - span.end(); - } - - return result; - } - case "updateService": { - Object result; - Span span = spanBuilder.startSpan(); - try (Scope ignored = span.makeCurrent()) { - - if (span.isRecording()) { - Service service = (Service) args[0]; - span.setAttribute(SemanticAttributes.HTTP_METHOD, HttpMethod.PUT); - span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, service.getName()); - span.setAttribute(NacosSemanticAttributes.GROUP, service.getGroupName()); - } - - result = method.invoke(namingClientProxy, args); - - } catch (InvocationTargetException e) { - Throwable targetException = e.getTargetException(); - span.recordException(targetException); - span.setStatus(StatusCode.ERROR, targetException.getClass().getSimpleName()); - throw targetException; - } finally { - span.end(); - } - - return result; - } - case "getServiceList": { - Object result; - Span span = spanBuilder.startSpan(); - try (Scope ignored = span.makeCurrent()) { - - if (span.isRecording()) { - switch (namingClientType) { - case "grpc": - span.setAttribute(SemanticAttributes.RPC_SYSTEM, "grpc"); - break; - case "http": - span.setAttribute(SemanticAttributes.HTTP_METHOD, HttpMethod.GET); - break; - default: - break; - } - span.setAttribute(NacosSemanticAttributes.PAGE_NO, (int) args[0]); - span.setAttribute(NacosSemanticAttributes.PAGE_SIZE, (int) args[1]); - span.setAttribute(NacosSemanticAttributes.GROUP, (String) args[2]); - } - - result = method.invoke(namingClientProxy, args); - - if (span.isRecording() && result != null) { - if (result instanceof ServiceListResponse) { - ServiceListResponse response = ((ServiceListResponse) result); - span.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_RESULT, - StringUtils.join(response.getServiceNames(), ", ")); - } else if (result instanceof String) { - span.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_RESULT, - (String) result); - } - } - - } catch (InvocationTargetException e) { - Throwable targetException = e.getTargetException(); - span.recordException(targetException); - span.setStatus(StatusCode.ERROR, targetException.getClass().getSimpleName()); - throw targetException; - } finally { - span.end(); - } - - return result; - } - case "subscribe": - case "unsubscribe": - case "isSubscribed": { - Object result; - Span span = spanBuilder.startSpan(); - try (Scope ignored = span.makeCurrent()) { - - if (span.isRecording()) { - span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, (String) args[0]); - span.setAttribute(NacosSemanticAttributes.GROUP, (String) args[1]); - span.setAttribute(NacosSemanticAttributes.CLUSTER, (String) args[2]); - } - - result = method.invoke(namingClientProxy, args); - - } catch (InvocationTargetException e) { - Throwable targetException = e.getTargetException(); - span.recordException(targetException); - span.setStatus(StatusCode.ERROR, targetException.getClass().getSimpleName()); - throw targetException; - } finally { - span.end(); - } - - return result; - } - case "serverHealthy": { - Object result; - Span span = spanBuilder.startSpan(); - try (Scope ignored = span.makeCurrent()) { - - result = method.invoke(namingClientProxy, args); - - if (span.isRecording() && result != null) { - boolean isHealthy = (boolean) result; - if (isHealthy) { - span.setStatus(StatusCode.OK, "Server is up"); - } else { - span.setStatus(StatusCode.ERROR, "Server is down"); - } - } - - } catch (InvocationTargetException e) { - Throwable targetException = e.getTargetException(); - span.recordException(targetException); - span.setStatus(StatusCode.ERROR, targetException.getClass().getSimpleName()); - throw targetException; - } finally { - span.end(); - } - - return result; - } - default: - break; - } - - try { - return method.invoke(namingClientProxy, args); - } catch (InvocationTargetException e) { - throw e.getTargetException(); - } - }); - } - - public static NamingGrpcRedoServiceTraceProxy getNamingGrpcRedoServiceTraceProxy( - NamingGrpcRedoService namingGrpcRedoService) { - return (NamingGrpcRedoServiceTraceProxy) Proxy.newProxyInstance(TraceDynamicProxy.class.getClassLoader(), - new Class[] {NamingGrpcRedoServiceTraceProxy.class}, (proxy, method, args) -> { - String methodName = method.getName(); - - SpanBuilder spanBuilder = NamingTrace.getClientNamingWorkerSpanBuilder(methodName); - spanBuilder.setAttribute(SemanticAttributes.CODE_NAMESPACE, - namingGrpcRedoService.getClass().getName()); - spanBuilder.setAttribute(SemanticAttributes.CODE_FUNCTION, methodName); - spanBuilder.setAttribute(NacosSemanticAttributes.NAMESPACE, namingGrpcRedoService.getNamespace()); - - switch (methodName) { - case "cacheInstanceForRedo": { - Object result; - Span span = spanBuilder.startSpan(); - try (Scope ignored = span.makeCurrent()) { - - if (span.isRecording()) { - span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, (String) args[0]); - span.setAttribute(NacosSemanticAttributes.GROUP, (String) args[1]); - String instanceString; - Object instanceArg = args[2]; - if (instanceArg instanceof Instance) { - instanceString = instanceArg.toString(); - } else { - List instanceList = (List) instanceArg; - instanceString = StringUtils.join(instanceList, ", "); - } - span.setAttribute(NacosSemanticAttributes.INSTANCE, instanceString); - } - - result = method.invoke(namingGrpcRedoService, args); - - } catch (InvocationTargetException e) { - Throwable targetException = e.getTargetException(); - span.recordException(targetException); - span.setStatus(StatusCode.ERROR, targetException.getClass().getSimpleName()); - throw targetException; - } finally { - span.end(); - } - - return result; - } - case "instanceRegistered": - case "instanceDeregister": - case "instanceDeregistered": { - Object result; - Span span = spanBuilder.startSpan(); - try (Scope ignored = span.makeCurrent()) { - - if (span.isRecording()) { - span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, (String) args[0]); - span.setAttribute(NacosSemanticAttributes.GROUP, (String) args[1]); - } - - result = method.invoke(namingGrpcRedoService, args); - - } catch (InvocationTargetException e) { - Throwable targetException = e.getTargetException(); - span.recordException(targetException); - span.setStatus(StatusCode.ERROR, targetException.getClass().getSimpleName()); - throw targetException; - } finally { - span.end(); - } - - return result; - } - case "cacheSubscriberForRedo": - case "subscriberRegistered": - case "subscriberDeregister": - case "isSubscriberRegistered": - case "removeSubscriberForRedo": { - Object result; - Span span = spanBuilder.startSpan(); - try (Scope ignored = span.makeCurrent()) { - - if (span.isRecording()) { - span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, (String) args[0]); - span.setAttribute(NacosSemanticAttributes.GROUP, (String) args[1]); - span.setAttribute(NacosSemanticAttributes.CLUSTER, (String) args[2]); - } - - result = method.invoke(namingGrpcRedoService, args); - - } catch (InvocationTargetException e) { - Throwable targetException = e.getTargetException(); - span.recordException(targetException); - span.setStatus(StatusCode.ERROR, targetException.getClass().getSimpleName()); - throw targetException; - } finally { - span.end(); - } - - return result; - } - case "getRegisteredInstancesByKey": { - Object result; - Span span = spanBuilder.startSpan(); - try (Scope ignored = span.makeCurrent()) { - - if (span.isRecording()) { - span.setAttribute(NacosSemanticAttributes.SERVICE_NAME, (String) args[0]); - } - - result = method.invoke(namingGrpcRedoService, args); - - if (span.isRecording() && result instanceof InstanceRedoData) { - Instance instance = ((InstanceRedoData) result).get(); - span.setAttribute(NacosSemanticAttributes.RequestAttributes.REQUEST_RESULT, - instance.toString()); - } - - } catch (InvocationTargetException e) { - Throwable targetException = e.getTargetException(); - span.recordException(targetException); - span.setStatus(StatusCode.ERROR, targetException.getClass().getSimpleName()); - throw targetException; - } finally { - span.end(); - } - - return result; - } - default: - break; - } - - try { - return method.invoke(namingGrpcRedoService, args); - } catch (InvocationTargetException e) { - throw e.getTargetException(); - } - }); - } - - private static boolean isFail(int code) { - return code == HttpURLConnection.HTTP_INTERNAL_ERROR || code == HttpURLConnection.HTTP_BAD_GATEWAY - || code == HttpURLConnection.HTTP_UNAVAILABLE || code == HttpURLConnection.HTTP_NOT_FOUND; - } -} diff --git a/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ClientWorkerProxy.java b/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ClientWorkerProxy.java deleted file mode 100644 index 43f6ac1c426..00000000000 --- a/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ClientWorkerProxy.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * - * Copyright 1999-2023 Alibaba Group Holding Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package com.alibaba.nacos.client.monitor.delegate.config; - -import com.alibaba.nacos.api.config.listener.Listener; -import com.alibaba.nacos.api.exception.NacosException; -import com.alibaba.nacos.client.config.filter.impl.ConfigResponse; -import com.alibaba.nacos.client.config.impl.CacheData; -import com.alibaba.nacos.common.lifecycle.Closeable; - -import java.util.List; - -/** - * proxy interface for ClientWorker. - * - * @author FAWC438 - */ -public interface ClientWorkerProxy extends Closeable { - - /** - * Add listener to config. - * - * @param dataId dataId - * @param group group - * @param content content - * @param encryptedDataKey encryptedDataKey - * @param listeners listener - * @throws NacosException NacosException - */ - void addTenantListenersWithContent(String dataId, String group, String content, String encryptedDataKey, - List listeners) throws NacosException; - - /** - * Add listener to config. - * - * @param dataId dataId - * @param group group - * @param listeners listener - * @throws NacosException NacosException - */ - void addTenantListeners(String dataId, String group, List listeners) throws NacosException; - - /** - * Remove listener from config. - * - * @param dataId dataId - * @param group group - * @param listener listener - */ - void removeTenantListener(String dataId, String group, Listener listener); - - /** - * Get config from server. - * - * @param dataId dataId - * @param group group - * @param tenant tenant - * @param readTimeout readTimeout - * @param notify notify - * @return ConfigResponse - * @throws NacosException NacosException - */ - ConfigResponse getServerConfig(String dataId, String group, String tenant, long readTimeout, boolean notify) - throws NacosException; - - /** - * Remove all listeners from config. - * - * @param dataId dataId - * @param group group - * @param tenant tenant - * @param tag tag - * @return boolean - * @throws NacosException NacosException - */ - boolean removeConfig(String dataId, String group, String tenant, String tag) throws NacosException; - - /** - * Remove all listeners from config. - * - * @param dataId dataId - * @param group group - * @param tenant tenant - * @param appName appName - * @param tag tag - * @param betaIps betaIps - * @param content content - * @param encryptedDataKey encryptedDataKey - * @param casMd5 casMd5 - * @param type type - * @return boolean - * @throws NacosException NacosException - */ - boolean publishConfig(String dataId, String group, String tenant, String appName, String tag, String betaIps, - String content, String encryptedDataKey, String casMd5, String type) throws NacosException; - - - /** - * Add cache data if absent. - * - * @param dataId data id if data - * @param group group of data - * @return cache data - */ - CacheData addCacheDataIfAbsent(String dataId, String group); - - /** - * Add cache data if absent. - * - * @param dataId data id if data - * @param group group of data - * @param tenant tenant of data - * @return cache data - * @throws NacosException NacosException - */ - CacheData addCacheDataIfAbsent(String dataId, String group, String tenant) throws NacosException; - - /** - * Check whether the server is health. - * - * @return boolean - */ - boolean isHealthServer(); - - // Other necessary methods - - /** - * Get agent tenant. - * - * @return tenant - */ - String getAgentTenant(); - - /** - * Get agent name. - * - * @return name - */ - String getAgentName(); - -} diff --git a/client/src/test/java/com/alibaba/nacos/client/monitor/TraceDynamicProxyTest.java b/client/src/test/java/com/alibaba/nacos/client/monitor/TraceDynamicProxyTest.java deleted file mode 100644 index 9df13dcc815..00000000000 --- a/client/src/test/java/com/alibaba/nacos/client/monitor/TraceDynamicProxyTest.java +++ /dev/null @@ -1,491 +0,0 @@ -/* - * - * Copyright 1999-2023 Alibaba Group Holding Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package com.alibaba.nacos.client.monitor; - -import com.alibaba.nacos.api.config.listener.AbstractListener; -import com.alibaba.nacos.api.config.listener.Listener; -import com.alibaba.nacos.api.exception.NacosException; -import com.alibaba.nacos.api.naming.pojo.Instance; -import com.alibaba.nacos.api.naming.pojo.ListView; -import com.alibaba.nacos.api.naming.pojo.ServiceInfo; -import com.alibaba.nacos.api.naming.utils.NamingUtils; -import com.alibaba.nacos.api.selector.AbstractSelector; -import com.alibaba.nacos.api.selector.ExpressionSelector; -import com.alibaba.nacos.client.config.filter.impl.ConfigFilterChainManager; -import com.alibaba.nacos.client.config.http.HttpAgent; -import com.alibaba.nacos.client.config.http.ServerHttpAgent; -import com.alibaba.nacos.client.config.impl.ClientWorker; -import com.alibaba.nacos.client.config.impl.ServerListManager; -import com.alibaba.nacos.client.env.NacosClientProperties; -import com.alibaba.nacos.client.monitor.delegate.config.ClientWorkerProxy; -import com.alibaba.nacos.client.monitor.naming.NamingGrpcRedoServiceTraceProxy; -import com.alibaba.nacos.client.naming.cache.ServiceInfoHolder; -import com.alibaba.nacos.client.naming.core.ServiceInfoUpdateService; -import com.alibaba.nacos.client.naming.event.InstancesChangeNotifier; -import com.alibaba.nacos.client.naming.remote.NamingClientProxy; -import com.alibaba.nacos.client.naming.remote.NamingClientProxyDelegate; -import com.alibaba.nacos.client.naming.remote.gprc.NamingGrpcClientProxy; -import com.alibaba.nacos.client.naming.remote.gprc.redo.NamingGrpcRedoService; -import com.alibaba.nacos.common.utils.ReflectUtils; -import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.sdk.OpenTelemetrySdk; -import io.opentelemetry.sdk.common.CompletableResultCode; -import io.opentelemetry.sdk.trace.SdkTracerProvider; -import io.opentelemetry.sdk.trace.data.SpanData; -import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; -import io.opentelemetry.sdk.trace.export.SpanExporter; -import org.junit.After; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; -import org.mockito.Mockito; - -import javax.annotation.ParametersAreNonnullByDefault; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Properties; -import java.util.concurrent.ScheduledExecutorService; - -public class TraceDynamicProxyTest { - - public static OpenTelemetry testOpenTelemetry = null; - - public static TraceDynamicProxyTest.TestExporter testExporter = null; - - @BeforeClass - public static void init() { - testExporter = new TraceDynamicProxyTest.TestExporter(); - testOpenTelemetry = OpenTelemetrySdk.builder().setTracerProvider( - SdkTracerProvider.builder().addSpanProcessor(SimpleSpanProcessor.create(testExporter)).build()).build(); - TraceMonitor.setOpenTelemetry(testOpenTelemetry); - } - - @After - public void clear() { - testExporter.exportedSpans.clear(); - } - - @Test - public void testGetClientWorkerTraceProxyListener() throws NacosException { - Properties prop = new Properties(); - ConfigFilterChainManager filter = new ConfigFilterChainManager(new Properties()); - ServerListManager serverListManager = Mockito.mock(ServerListManager.class); - - final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(prop); - ClientWorker clientWorker = new ClientWorker(filter, serverListManager, nacosClientProperties); - ClientWorkerProxy traceProxy = TraceDynamicProxy.getClientWorkerTraceProxy(clientWorker); - - Listener listener = new AbstractListener() { - @Override - public void receiveConfigInfo(String configInfo) { - } - }; - - String dataId = "a"; - String group = "b"; - String content = "c"; - - traceProxy.addTenantListenersWithContent(dataId, group, content, null, Collections.singletonList(listener)); - Assert.assertEquals("Nacos.client.config.worker / addCacheDataIfAbsent", - testExporter.exportedSpans.get(0).getName()); - Assert.assertEquals("Nacos.client.config.service / addTenantListenersWithContent", - testExporter.exportedSpans.get(1).getName()); - testExporter.exportedSpans.clear(); - - traceProxy.addTenantListeners(dataId, group, Collections.singletonList(listener)); - Assert.assertEquals("Nacos.client.config.worker / addCacheDataIfAbsent", - testExporter.exportedSpans.get(0).getName()); - Assert.assertEquals("Nacos.client.config.service / addTenantListeners", - testExporter.exportedSpans.get(1).getName()); - testExporter.exportedSpans.clear(); - - traceProxy.removeTenantListener(dataId, group, listener); - Assert.assertEquals("Nacos.client.config.service / removeTenantListener", - testExporter.exportedSpans.get(0).getName()); - testExporter.exportedSpans.clear(); - - clientWorker.shutdown(); - } - - @Test - public void testGetClientWorkerTraceProxyConfig() throws NacosException { - Properties prop = new Properties(); - ConfigFilterChainManager filter = new ConfigFilterChainManager(new Properties()); - ServerListManager serverListManager = Mockito.mock(ServerListManager.class); - - final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(prop); - ClientWorker clientWorker = new ClientWorker(filter, serverListManager, nacosClientProperties); - ClientWorkerProxy traceProxy = TraceDynamicProxy.getClientWorkerTraceProxy(clientWorker); - - String dataId = "a"; - String group = "b"; - String tenant = "c"; - - try { - traceProxy.getServerConfig(dataId, group, tenant, 3000, false); - Assert.fail(); - } catch (NacosException e) { - Assert.assertEquals("Client not connected, current status:STARTING", e.getErrMsg()); - Assert.assertEquals(-401, e.getErrCode()); - } - Assert.assertEquals("Nacos.client.config.service / getServerConfig", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1).getName()); - testExporter.exportedSpans.clear(); - - String tag = "tag"; - - try { - traceProxy.removeConfig(dataId, group, tenant, tag); - Assert.fail(); - } catch (NacosException e) { - Assert.assertEquals("Client not connected, current status:STARTING", e.getErrMsg()); - Assert.assertEquals(-401, e.getErrCode()); - } - Assert.assertEquals("Nacos.client.config.service / removeConfig", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1).getName()); - testExporter.exportedSpans.clear(); - - String content = "d"; - String appName = "app"; - String betaIps = "1.1.1.1"; - String casMd5 = "1111"; - String type = "properties"; - - boolean b = traceProxy.publishConfig(dataId, group, tenant, appName, tag, betaIps, content, null, casMd5, type); - Assert.assertFalse(b); - Assert.assertEquals("Nacos.client.config.service / publishConfig", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1).getName()); - testExporter.exportedSpans.clear(); - - clientWorker.shutdown(); - } - - @Test - public void testGetClientWorkerTraceProxyIsHealthServer() - throws NacosException, NoSuchFieldException, IllegalAccessException { - Properties prop = new Properties(); - ConfigFilterChainManager filter = new ConfigFilterChainManager(new Properties()); - ServerListManager serverListManager = Mockito.mock(ServerListManager.class); - - final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(prop); - ClientWorker clientWorker = new ClientWorker(filter, serverListManager, nacosClientProperties); - ClientWorker.ConfigRpcTransportClient client = Mockito.mock(ClientWorker.ConfigRpcTransportClient.class); - Mockito.when(client.isHealthServer()).thenReturn(Boolean.TRUE); - - Field declaredField = ClientWorker.class.getDeclaredField("agent"); - declaredField.setAccessible(true); - declaredField.set(clientWorker, client); - - ClientWorkerProxy traceProxy = TraceDynamicProxy.getClientWorkerTraceProxy(clientWorker); - - Assert.assertTrue(traceProxy.isHealthServer()); - Assert.assertEquals("Nacos.client.config.service / isHealthServer", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1).getName()); - - clientWorker.shutdown(); - } - - @Test - public void testGetConfigRpcTransportClientTraceProxy() throws NacosException { - Properties prop = new Properties(); - ConfigFilterChainManager filter = new ConfigFilterChainManager(new Properties()); - ServerListManager serverListManager = Mockito.mock(ServerListManager.class); - - final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(prop); - ClientWorker clientWorker = new ClientWorker(filter, serverListManager, nacosClientProperties); - ClientWorkerProxy traceProxy = TraceDynamicProxy.getClientWorkerTraceProxy(clientWorker); - - String dataId = "a"; - String group = "b"; - String tenant = "c"; - - try { - traceProxy.getServerConfig(dataId, group, tenant, 3000, false); - Assert.fail(); - } catch (NacosException e) { - Assert.assertEquals("Client not connected, current status:STARTING", e.getErrMsg()); - Assert.assertEquals(-401, e.getErrCode()); - } - Assert.assertEquals("Nacos.client.config.worker / queryConfig", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 2).getName()); - Assert.assertEquals("Nacos.client.config.rpc / GRPC", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 3).getName()); - testExporter.exportedSpans.clear(); - - String tag = "tag"; - - try { - traceProxy.removeConfig(dataId, group, tenant, tag); - Assert.fail(); - } catch (NacosException e) { - Assert.assertEquals("Client not connected, current status:STARTING", e.getErrMsg()); - Assert.assertEquals(-401, e.getErrCode()); - } - Assert.assertEquals("Nacos.client.config.worker / removeConfig", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 2).getName()); - Assert.assertEquals("Nacos.client.config.rpc / GRPC", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 3).getName()); - testExporter.exportedSpans.clear(); - - String content = "d"; - String appName = "app"; - String betaIps = "1.1.1.1"; - String casMd5 = "1111"; - String type = "properties"; - - boolean b = traceProxy.publishConfig(dataId, group, tenant, appName, tag, betaIps, content, null, casMd5, type); - Assert.assertFalse(b); - Assert.assertEquals("Nacos.client.config.worker / publishConfig", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 2).getName()); - Assert.assertEquals("Nacos.client.config.rpc / GRPC", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 3).getName()); - testExporter.exportedSpans.clear(); - - clientWorker.shutdown(); - } - - @Test - public void testGetHttpAgentTraceProxy() throws Exception { - ServerListManager serverListManager = Mockito.mock(ServerListManager.class); - HttpAgent httpAgent = new ServerHttpAgent(serverListManager); - HttpAgent agent = TraceDynamicProxy.getHttpAgentTraceProxy(httpAgent); - - try { - agent.httpGet("/aa", new HashMap<>(), new HashMap<>(), "UTF-8", 1L); - Assert.fail(); - } catch (IllegalArgumentException e) { - Assert.assertEquals("URI is not absolute", e.getMessage()); - } - Assert.assertEquals("Nacos.client.config.http / GET", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1).getName()); - - try { - agent.httpPost("/bb", new HashMap<>(), new HashMap<>(), "UTF-8", 1L); - Assert.fail(); - } catch (IllegalArgumentException e) { - Assert.assertEquals("URI is not absolute", e.getMessage()); - } - Assert.assertEquals("Nacos.client.config.http / POST", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1).getName()); - - try { - agent.httpDelete("/cc", new HashMap<>(), new HashMap<>(), "UTF-8", 1L); - Assert.fail(); - } catch (IllegalArgumentException e) { - Assert.assertEquals("URI is not absolute", e.getMessage()); - } - Assert.assertEquals("Nacos.client.config.http / DELETE", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1).getName()); - - agent.shutdown(); - } - - @Test - public void testGetNamingClientProxyTraceProxy() - throws NacosException, IllegalAccessException, NoSuchFieldException { - String ns = "ns1"; - ServiceInfoHolder holder = Mockito.mock(ServiceInfoHolder.class); - Properties props = new Properties(); - props.setProperty("serverAddr", "localhost"); - final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(props); - InstancesChangeNotifier notifier = new InstancesChangeNotifier(); - NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, nacosClientProperties, notifier); - - NamingGrpcClientProxy mockGrpcClient = Mockito.mock(NamingGrpcClientProxy.class); - Field grpcClientProxyField = NamingClientProxyDelegate.class.getDeclaredField("grpcClientProxy"); - grpcClientProxyField.setAccessible(true); - grpcClientProxyField.set(delegate, mockGrpcClient); - - ServiceInfoUpdateService serviceInfoUpdateService = Mockito.mock(ServiceInfoUpdateService.class); - Field serviceInfoUpdateServiceField = NamingClientProxyDelegate.class.getDeclaredField( - "serviceInfoUpdateService"); - serviceInfoUpdateServiceField.setAccessible(true); - serviceInfoUpdateServiceField.set(delegate, serviceInfoUpdateService); - - Instance instance = new Instance(); - String serviceName = "service1"; - String groupName = "group1"; - instance.setServiceName(serviceName); - instance.setClusterName(groupName); - instance.setIp("1.1.1.1"); - instance.setPort(1); - instance.setEphemeral(true); - - NamingClientProxy proxy = TraceDynamicProxy.getNamingClientProxyTraceProxy(delegate); - - Mockito.doNothing().when(mockGrpcClient).registerService(serviceName, groupName, instance); - proxy.registerService(serviceName, groupName, instance); - Assert.assertEquals("Nacos.client.naming.service / registerService", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1).getName()); - - Mockito.doNothing().when(mockGrpcClient).deregisterService(serviceName, groupName, instance); - proxy.deregisterService(serviceName, groupName, instance); - Assert.assertEquals("Nacos.client.naming.service / deregisterService", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1).getName()); - - Mockito.doNothing().when(mockGrpcClient) - .batchRegisterService(serviceName, groupName, Collections.singletonList(instance)); - proxy.batchRegisterService(serviceName, groupName, Collections.singletonList(instance)); - Assert.assertEquals("Nacos.client.naming.service / batchRegisterService", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1).getName()); - - Mockito.doNothing().when(mockGrpcClient) - .batchDeregisterService(serviceName, groupName, Collections.singletonList(instance)); - proxy.batchDeregisterService(serviceName, groupName, Collections.singletonList(instance)); - Assert.assertEquals("Nacos.client.naming.service / batchDeregisterService", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1).getName()); - - String clusters = "cluster1"; - int udpPort = 1111; - ServiceInfo serviceInfo = new ServiceInfo(); - - Mockito.when(mockGrpcClient.queryInstancesOfService(serviceName, groupName, clusters, udpPort, false)) - .thenReturn(serviceInfo); - ServiceInfo result = proxy.queryInstancesOfService(serviceName, groupName, clusters, udpPort, false); - Assert.assertEquals(serviceInfo, result); - Assert.assertEquals("Nacos.client.naming.service / queryInstancesOfService", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1).getName()); - - AbstractSelector selector = new ExpressionSelector(); - int pageNo = 1; - int pageSize = 10; - ListView listView = new ListView<>(); - - Mockito.when(mockGrpcClient.getServiceList(pageNo, pageSize, groupName, selector)).thenReturn(listView); - ListView resultList = proxy.getServiceList(pageNo, pageSize, groupName, selector); - Assert.assertEquals(listView, resultList); - Assert.assertEquals("Nacos.client.naming.service / getServiceList", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1).getName()); - - Mockito.when(holder.getServiceInfoMap()).thenReturn(new HashMap<>()); - Mockito.when(holder.processServiceInfo(serviceInfo)).thenReturn(serviceInfo); - Mockito.doNothing().when(serviceInfoUpdateService).scheduleUpdateIfAbsent(serviceName, groupName, clusters); - Mockito.when(mockGrpcClient.subscribe(serviceName, groupName, clusters)).thenReturn(serviceInfo); - result = proxy.subscribe(serviceName, groupName, clusters); - Assert.assertEquals(serviceInfo, result); - Assert.assertEquals("Nacos.client.naming.service / subscribe", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1).getName()); - - Mockito.doNothing().when(serviceInfoUpdateService).stopUpdateIfContain(serviceName, groupName, clusters); - Mockito.doNothing().when(mockGrpcClient).unsubscribe(serviceName, groupName, clusters); - proxy.unsubscribe(serviceName, groupName, clusters); - Assert.assertEquals("Nacos.client.naming.service / unsubscribe", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1).getName()); - - Mockito.when(mockGrpcClient.isSubscribed(serviceName, groupName, clusters)).thenReturn(Boolean.TRUE); - boolean isSubscribed = proxy.isSubscribed(serviceName, groupName, clusters); - Assert.assertTrue(isSubscribed); - Assert.assertEquals("Nacos.client.naming.service / isSubscribed", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1).getName()); - - Mockito.when(mockGrpcClient.serverHealthy()).thenReturn(Boolean.TRUE); - boolean serverHealthy = proxy.serverHealthy(); - Assert.assertTrue(serverHealthy); - Assert.assertEquals("Nacos.client.naming.service / serverHealthy", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1).getName()); - - delegate.shutdown(); - } - - @Test - public void testGetNamingGrpcRedoServiceTraceProxy() { - NamingGrpcClientProxy clientProxy = Mockito.mock(NamingGrpcClientProxy.class); - NamingGrpcRedoService redoService = new NamingGrpcRedoService(clientProxy); - ScheduledExecutorService redoExecutor = (ScheduledExecutorService) ReflectUtils.getFieldValue(redoService, - "redoExecutor"); - redoExecutor.shutdownNow(); - - String service = "service"; - String group = "group"; - Instance instance = new Instance(); - - NamingGrpcRedoServiceTraceProxy proxy = TraceDynamicProxy.getNamingGrpcRedoServiceTraceProxy(redoService); - - proxy.cacheInstanceForRedo(service, group, instance); - Assert.assertEquals("Nacos.client.naming.worker / cacheInstanceForRedo", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1).getName()); - - proxy.instanceDeregistered(service, group); - Assert.assertEquals("Nacos.client.naming.worker / instanceDeregistered", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1).getName()); - - proxy.instanceDeregister(service, group); - Assert.assertEquals("Nacos.client.naming.worker / instanceDeregister", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1).getName()); - - proxy.instanceDeregistered(service, group); - Assert.assertEquals("Nacos.client.naming.worker / instanceDeregistered", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1).getName()); - - String cluster = "cluster"; - - proxy.cacheSubscriberForRedo(service, group, cluster); - Assert.assertEquals("Nacos.client.naming.worker / cacheSubscriberForRedo", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1).getName()); - - proxy.subscriberRegistered(service, group, cluster); - Assert.assertEquals("Nacos.client.naming.worker / subscriberRegistered", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1).getName()); - - proxy.subscriberDeregister(service, group, cluster); - Assert.assertEquals("Nacos.client.naming.worker / subscriberDeregister", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1).getName()); - - proxy.isSubscriberRegistered(service, group, cluster); - Assert.assertEquals("Nacos.client.naming.worker / isSubscriberRegistered", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1).getName()); - - proxy.removeSubscriberForRedo(service, group, cluster); - Assert.assertEquals("Nacos.client.naming.worker / removeSubscriberForRedo", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1).getName()); - - String combineKey = NamingUtils.getGroupedName(service, group); - proxy.getRegisteredInstancesByKey(combineKey); - Assert.assertEquals("Nacos.client.naming.worker / getRegisteredInstancesByKey", - testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1).getName()); - - redoService.shutdown(); - } - - public static class TestExporter implements SpanExporter { - - public final List exportedSpans = Collections.synchronizedList(new ArrayList<>()); - - @ParametersAreNonnullByDefault - @Override - public CompletableResultCode export(Collection collection) { - exportedSpans.addAll(collection); - return CompletableResultCode.ofSuccess(); - } - - @Override - public CompletableResultCode flush() { - return CompletableResultCode.ofSuccess(); - } - - @Override - public CompletableResultCode shutdown() { - return CompletableResultCode.ofSuccess(); - } - } -} diff --git a/client/src/test/java/com/alibaba/nacos/client/monitor/delegate/config/ServerHttpAgentTraceDelegateTest.java b/client/src/test/java/com/alibaba/nacos/client/monitor/delegate/config/ServerHttpAgentTraceDelegateTest.java new file mode 100644 index 00000000000..ac5d0c6be57 --- /dev/null +++ b/client/src/test/java/com/alibaba/nacos/client/monitor/delegate/config/ServerHttpAgentTraceDelegateTest.java @@ -0,0 +1,113 @@ +/* + * + * Copyright 1999-2023 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.client.monitor.delegate.config; + +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.client.config.http.HttpAgent; +import com.alibaba.nacos.client.config.impl.ServerListManager; +import com.alibaba.nacos.client.monitor.delegate.OpenTelemetryBaseTest; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import java.util.HashMap; +import java.util.Map; + +public class ServerHttpAgentTraceDelegateTest extends OpenTelemetryBaseTest { + + private HttpAgent agent; + + @Before + public void initAgent() { + ServerListManager serverListManager = Mockito.mock(ServerListManager.class); + agent = new ServerHttpAgentTraceDelegate(serverListManager); + } + + @After + public void closeAgent() throws NacosException { + agent.shutdown(); + } + + @Test + public void testHttpGet() throws Exception { + + String path = "/aa"; + Map headers = new HashMap<>(); + Map paramValues = new HashMap<>(); + String encoding = "UTF-8"; + long readTimeoutMs = 1L; + + try { + agent.httpGet(path, headers, paramValues, encoding, readTimeoutMs); + Assert.fail(); + } catch (IllegalArgumentException e) { + Assert.assertEquals("URI is not absolute", e.getMessage()); + } + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + SpanData spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1); + Assert.assertEquals("Nacos.client.config.http / GET", spanData.getName()); + Assert.assertEquals(path, spanData.getAttributes().get(SemanticAttributes.HTTP_URL)); + } + + @Test + public void testHttpPost() throws Exception { + + String path = "/aa"; + Map headers = new HashMap<>(); + Map paramValues = new HashMap<>(); + String encoding = "UTF-8"; + long readTimeoutMs = 1L; + + try { + agent.httpPost(path, headers, paramValues, encoding, readTimeoutMs); + Assert.fail(); + } catch (IllegalArgumentException e) { + Assert.assertEquals("URI is not absolute", e.getMessage()); + } + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + SpanData spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1); + Assert.assertEquals("Nacos.client.config.http / POST", spanData.getName()); + Assert.assertEquals(path, spanData.getAttributes().get(SemanticAttributes.HTTP_URL)); + } + + @Test + public void testHttpDelete() throws Exception { + + String path = "/aa"; + Map headers = new HashMap<>(); + Map paramValues = new HashMap<>(); + String encoding = "UTF-8"; + long readTimeoutMs = 1L; + + try { + agent.httpDelete(path, headers, paramValues, encoding, readTimeoutMs); + Assert.fail(); + } catch (IllegalArgumentException e) { + Assert.assertEquals("URI is not absolute", e.getMessage()); + } + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + SpanData spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1); + Assert.assertEquals("Nacos.client.config.http / DELETE", spanData.getName()); + Assert.assertEquals(path, spanData.getAttributes().get(SemanticAttributes.HTTP_URL)); + } +} diff --git a/client/src/test/java/com/alibaba/nacos/client/monitor/delegate/naming/NamingClientProxyTraceDelegateTest.java b/client/src/test/java/com/alibaba/nacos/client/monitor/delegate/naming/NamingClientProxyTraceDelegateTest.java new file mode 100644 index 00000000000..f0c32027ce3 --- /dev/null +++ b/client/src/test/java/com/alibaba/nacos/client/monitor/delegate/naming/NamingClientProxyTraceDelegateTest.java @@ -0,0 +1,352 @@ +/* + * + * Copyright 1999-2023 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.client.monitor.delegate.naming; + +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.naming.pojo.Instance; +import com.alibaba.nacos.api.naming.pojo.ListView; +import com.alibaba.nacos.api.naming.pojo.ServiceInfo; +import com.alibaba.nacos.api.selector.AbstractSelector; +import com.alibaba.nacos.api.selector.ExpressionSelector; +import com.alibaba.nacos.client.env.NacosClientProperties; +import com.alibaba.nacos.client.monitor.delegate.OpenTelemetryBaseTest; +import com.alibaba.nacos.client.naming.cache.ServiceInfoHolder; +import com.alibaba.nacos.client.naming.core.ServiceInfoUpdateService; +import com.alibaba.nacos.client.naming.event.InstancesChangeNotifier; +import com.alibaba.nacos.client.naming.remote.NamingClientProxy; +import com.alibaba.nacos.client.naming.remote.NamingClientProxyDelegate; +import com.alibaba.nacos.client.naming.remote.gprc.NamingGrpcClientProxy; +import com.alibaba.nacos.common.constant.NacosSemanticAttributes; +import com.alibaba.nacos.common.utils.StringUtils; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.sdk.trace.data.SpanData; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Properties; + +public class NamingClientProxyTraceDelegateTest extends OpenTelemetryBaseTest { + + private NamingClientProxy proxy; + + private NamingClientProxyDelegate delegate; + + private NamingClientProxy mockGrpcClient; + + private ServiceInfoHolder mockHolder; + + // private ServiceInfoUpdateService mockServiceInfoUpdateService; + + private final String serviceName = "testService"; + + private final String groupName = "testGroup"; + + @Before + public void initProxy() throws NacosException, NoSuchFieldException, IllegalAccessException { + String nameSpace = "testNameSpace"; + + mockHolder = Mockito.mock(ServiceInfoHolder.class); + + Properties props = new Properties(); + props.setProperty("serverAddr", "localhost"); + final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(props); + InstancesChangeNotifier notifier = new InstancesChangeNotifier(); + delegate = new NamingClientProxyDelegate(nameSpace, mockHolder, nacosClientProperties, notifier); + + mockGrpcClient = Mockito.mock(NamingGrpcClientProxy.class); + Field grpcClientProxyField = NamingClientProxyDelegate.class.getDeclaredField("grpcClientProxy"); + grpcClientProxyField.setAccessible(true); + grpcClientProxyField.set(delegate, mockGrpcClient); + + proxy = new NamingClientProxyTraceDelegate(delegate); + } + + @After + public void closeProxy() throws NacosException { + delegate.shutdown(); + proxy.shutdown(); + } + + @Test + public void testRegisterService() throws NacosException { + + Instance instance = new Instance(); + instance.setServiceName(serviceName); + instance.setClusterName(groupName); + instance.setIp("1.1.1.1"); + instance.setPort(1); + instance.setEphemeral(true); + + Mockito.doNothing().when(mockGrpcClient).registerService(serviceName, groupName, instance); + proxy.registerService(serviceName, groupName, instance); + + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + SpanData spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1); + Assert.assertEquals("Nacos.client.naming.service / registerService", spanData.getName()); + + Assert.assertEquals(serviceName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.SERVICE_NAME))); + Assert.assertEquals(groupName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.GROUP))); + Assert.assertEquals(instance.toString(), + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.INSTANCE))); + } + + @Test + public void testBatchRegisterService() throws NacosException { + + Instance instance = new Instance(); + instance.setServiceName(serviceName); + instance.setClusterName(groupName); + instance.setIp("1.1.1.1"); + instance.setPort(1); + instance.setEphemeral(true); + + List instances = Collections.singletonList(instance); + + Mockito.doNothing().when(mockGrpcClient).batchRegisterService(serviceName, groupName, instances); + proxy.batchRegisterService(serviceName, groupName, instances); + + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + SpanData spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1); + Assert.assertEquals("Nacos.client.naming.service / batchRegisterService", spanData.getName()); + + Assert.assertEquals(serviceName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.SERVICE_NAME))); + Assert.assertEquals(groupName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.GROUP))); + Assert.assertEquals(StringUtils.join(instances, ", "), + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.INSTANCE))); + } + + @Test + public void testBatchDeregisterService() throws NacosException { + + Instance instance = new Instance(); + instance.setServiceName(serviceName); + instance.setClusterName(groupName); + instance.setIp("1.1.1.1"); + instance.setPort(1); + instance.setEphemeral(true); + + List instances = Collections.singletonList(instance); + + Mockito.doNothing().when(mockGrpcClient).batchDeregisterService(serviceName, groupName, instances); + proxy.batchDeregisterService(serviceName, groupName, instances); + + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + SpanData spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1); + Assert.assertEquals("Nacos.client.naming.service / batchDeregisterService", spanData.getName()); + + Assert.assertEquals(serviceName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.SERVICE_NAME))); + Assert.assertEquals(groupName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.GROUP))); + Assert.assertEquals(StringUtils.join(instances, ", "), + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.INSTANCE))); + } + + @Test + public void testDeregisterService() throws NacosException { + + Instance instance = new Instance(); + instance.setServiceName(serviceName); + instance.setClusterName(groupName); + instance.setIp("1.1.1.1"); + instance.setPort(1); + instance.setEphemeral(true); + + Mockito.doNothing().when(mockGrpcClient).deregisterService(serviceName, groupName, instance); + proxy.deregisterService(serviceName, groupName, instance); + + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + SpanData spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1); + Assert.assertEquals("Nacos.client.naming.service / deregisterService", spanData.getName()); + + Assert.assertEquals(serviceName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.SERVICE_NAME))); + Assert.assertEquals(groupName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.GROUP))); + Assert.assertEquals(instance.toString(), + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.INSTANCE))); + } + + @Test + public void testQueryInstancesOfService() throws NacosException { + + String clusters = "testCluster"; + int udpPort = 1111; + ServiceInfo serviceInfo = new ServiceInfo(); + + Mockito.when(mockGrpcClient.queryInstancesOfService(serviceName, groupName, clusters, udpPort, false)) + .thenReturn(serviceInfo); + ServiceInfo result = proxy.queryInstancesOfService(serviceName, groupName, clusters, udpPort, false); + Assert.assertEquals(serviceInfo, result); + + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + SpanData spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1); + Assert.assertEquals("Nacos.client.naming.service / queryInstancesOfService", spanData.getName()); + + Assert.assertEquals(serviceName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.SERVICE_NAME))); + Assert.assertEquals(groupName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.GROUP))); + Assert.assertEquals(clusters, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.CLUSTER))); + } + + @Test + public void testGetServiceList() throws NacosException { + + AbstractSelector selector = new ExpressionSelector(); + int pageNo = 1; + int pageSize = 10; + ListView listView = new ListView<>(); + + Mockito.when(mockGrpcClient.getServiceList(pageNo, pageSize, groupName, selector)).thenReturn(listView); + ListView resultList = proxy.getServiceList(pageNo, pageSize, groupName, selector); + Assert.assertEquals(listView, resultList); + + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + SpanData spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1); + Assert.assertEquals("Nacos.client.naming.service / getServiceList", spanData.getName()); + + Assert.assertEquals(groupName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.GROUP))); + Assert.assertEquals(Long.valueOf(pageNo), + spanData.getAttributes().get(AttributeKey.longKey(NacosSemanticAttributes.PAGE_NO))); + } + + @Test + public void testSubscribe() throws IllegalAccessException, NoSuchFieldException, NacosException { + + ServiceInfoUpdateService mockServiceInfoUpdateService = Mockito.mock(ServiceInfoUpdateService.class); + Field serviceInfoUpdateServiceField = NamingClientProxyDelegate.class.getDeclaredField( + "serviceInfoUpdateService"); + serviceInfoUpdateServiceField.setAccessible(true); + serviceInfoUpdateServiceField.set(delegate, mockServiceInfoUpdateService); + + String clusters = "testCluster"; + ServiceInfo serviceInfo = new ServiceInfo(); + + Mockito.when(mockHolder.getServiceInfoMap()).thenReturn(new HashMap<>()); + Mockito.when(mockHolder.processServiceInfo(serviceInfo)).thenReturn(serviceInfo); + Mockito.doNothing().when(mockServiceInfoUpdateService).scheduleUpdateIfAbsent(serviceName, groupName, clusters); + Mockito.when(mockGrpcClient.subscribe(serviceName, groupName, clusters)).thenReturn(serviceInfo); + ServiceInfo result = proxy.subscribe(serviceName, groupName, clusters); + Assert.assertEquals(serviceInfo, result); + + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + SpanData spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1); + Assert.assertEquals("Nacos.client.naming.service / subscribe", spanData.getName()); + + Assert.assertEquals(serviceName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.SERVICE_NAME))); + Assert.assertEquals(groupName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.GROUP))); + Assert.assertEquals(clusters, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.CLUSTER))); + } + + @Test + public void testUnsubscribe() throws NacosException, IllegalAccessException, NoSuchFieldException { + + ServiceInfoUpdateService mockServiceInfoUpdateService = Mockito.mock(ServiceInfoUpdateService.class); + Field serviceInfoUpdateServiceField = NamingClientProxyDelegate.class.getDeclaredField( + "serviceInfoUpdateService"); + serviceInfoUpdateServiceField.setAccessible(true); + serviceInfoUpdateServiceField.set(delegate, mockServiceInfoUpdateService); + + String clusters = "testCluster"; + + Mockito.doNothing().when(mockServiceInfoUpdateService).stopUpdateIfContain(serviceName, groupName, clusters); + Mockito.doNothing().when(mockGrpcClient).unsubscribe(serviceName, groupName, clusters); + proxy.unsubscribe(serviceName, groupName, clusters); + + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + SpanData spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1); + Assert.assertEquals("Nacos.client.naming.service / unsubscribe", spanData.getName()); + + Assert.assertEquals(serviceName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.SERVICE_NAME))); + Assert.assertEquals(groupName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.GROUP))); + Assert.assertEquals(clusters, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.CLUSTER))); + } + + @Test + public void testIsSubscribed() throws NacosException { + + String clusters = "testCluster"; + + Mockito.when(mockGrpcClient.isSubscribed(serviceName, groupName, clusters)).thenReturn(Boolean.TRUE); + boolean result = proxy.isSubscribed(serviceName, groupName, clusters); + Assert.assertTrue(result); + + Mockito.when(mockGrpcClient.isSubscribed(serviceName, groupName, clusters)).thenReturn(Boolean.FALSE); + result = proxy.isSubscribed(serviceName, groupName, clusters); + Assert.assertFalse(result); + + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + SpanData spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 2); + Assert.assertEquals("Nacos.client.naming.service / isSubscribed", spanData.getName()); + + Assert.assertEquals(serviceName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.SERVICE_NAME))); + Assert.assertEquals(groupName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.GROUP))); + Assert.assertEquals(clusters, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.CLUSTER))); + + spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1); + Assert.assertEquals("Nacos.client.naming.service / isSubscribed", spanData.getName()); + + Assert.assertEquals(serviceName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.SERVICE_NAME))); + Assert.assertEquals(groupName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.GROUP))); + Assert.assertEquals(clusters, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.CLUSTER))); + } + + @Test + public void testServerHealthy() { + Mockito.when(mockGrpcClient.serverHealthy()).thenReturn(Boolean.TRUE); + boolean result = proxy.serverHealthy(); + Assert.assertTrue(result); + + SpanData spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1); + Assert.assertEquals("Nacos.client.naming.service / serverHealthy", spanData.getName()); + + Mockito.when(mockGrpcClient.serverHealthy()).thenReturn(Boolean.FALSE); + result = proxy.serverHealthy(); + Assert.assertFalse(result); + + spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1); + Assert.assertEquals("Nacos.client.naming.service / serverHealthy", spanData.getName()); + } +} diff --git a/client/src/test/java/com/alibaba/nacos/client/monitor/delegate/naming/NamingGrpcRedoServiceTraceDelegateTest.java b/client/src/test/java/com/alibaba/nacos/client/monitor/delegate/naming/NamingGrpcRedoServiceTraceDelegateTest.java new file mode 100644 index 00000000000..c94f37c2bd8 --- /dev/null +++ b/client/src/test/java/com/alibaba/nacos/client/monitor/delegate/naming/NamingGrpcRedoServiceTraceDelegateTest.java @@ -0,0 +1,195 @@ +/* + * + * Copyright 1999-2023 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.client.monitor.delegate.naming; + +import com.alibaba.nacos.api.naming.pojo.Instance; +import com.alibaba.nacos.api.naming.utils.NamingUtils; +import com.alibaba.nacos.client.monitor.delegate.OpenTelemetryBaseTest; +import com.alibaba.nacos.client.naming.remote.gprc.NamingGrpcClientProxy; +import com.alibaba.nacos.client.naming.remote.gprc.redo.NamingGrpcRedoService; +import com.alibaba.nacos.common.constant.NacosSemanticAttributes; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.sdk.trace.data.SpanData; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import java.lang.reflect.Field; +import java.util.concurrent.ScheduledExecutorService; + +public class NamingGrpcRedoServiceTraceDelegateTest extends OpenTelemetryBaseTest { + + private final String serviceName = "testService"; + + private final String groupName = "testGroup"; + + private final String clusterName = "testCluster"; + + private final Instance instance = new Instance(); + + private NamingGrpcRedoServiceTraceDelegate delegate; + + @Before + public void initService() throws NoSuchFieldException, IllegalAccessException { + NamingGrpcClientProxy clientProxy = Mockito.mock(NamingGrpcClientProxy.class); + delegate = new NamingGrpcRedoServiceTraceDelegate(clientProxy); + + Field field = NamingGrpcRedoService.class.getDeclaredField("redoExecutor"); + field.setAccessible(true); + ScheduledExecutorService redoExecutor = (ScheduledExecutorService) field.get(delegate); + + redoExecutor.shutdownNow(); + } + + @After + public void shutdownService() { + delegate.shutdown(); + } + + @Test + public void testCacheInstanceForRedo() { + delegate.cacheInstanceForRedo(serviceName, groupName, instance); + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + SpanData spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1); + Assert.assertEquals("Nacos.client.naming.worker / cacheInstanceForRedo", spanData.getName()); + + Assert.assertEquals(serviceName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.SERVICE_NAME))); + Assert.assertEquals(groupName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.GROUP))); + Assert.assertEquals(instance.toString(), + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.INSTANCE))); + } + + @Test + public void testInstanceDeregistered() { + delegate.instanceDeregistered(serviceName, groupName); + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + SpanData spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1); + Assert.assertEquals("Nacos.client.naming.worker / instanceDeregistered", spanData.getName()); + + Assert.assertEquals(serviceName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.SERVICE_NAME))); + Assert.assertEquals(groupName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.GROUP))); + } + + @Test + public void testInstanceDeregister() { + delegate.instanceDeregister(serviceName, groupName); + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + SpanData spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1); + Assert.assertEquals("Nacos.client.naming.worker / instanceDeregister", spanData.getName()); + + Assert.assertEquals(serviceName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.SERVICE_NAME))); + Assert.assertEquals(groupName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.GROUP))); + } + + @Test + public void testCacheSubscriberForRedo() { + delegate.cacheSubscriberForRedo(serviceName, groupName, clusterName); + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + SpanData spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1); + Assert.assertEquals("Nacos.client.naming.worker / cacheSubscriberForRedo", spanData.getName()); + + Assert.assertEquals(serviceName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.SERVICE_NAME))); + Assert.assertEquals(groupName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.GROUP))); + Assert.assertEquals(clusterName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.CLUSTER))); + } + + @Test + public void testSubscriberRegistered() { + delegate.subscriberRegistered(serviceName, groupName, clusterName); + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + SpanData spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1); + Assert.assertEquals("Nacos.client.naming.worker / subscriberRegistered", spanData.getName()); + + Assert.assertEquals(serviceName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.SERVICE_NAME))); + Assert.assertEquals(groupName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.GROUP))); + Assert.assertEquals(clusterName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.CLUSTER))); + } + + @Test + public void testSubscriberDeregister() { + delegate.subscriberDeregister(serviceName, groupName, clusterName); + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + SpanData spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1); + Assert.assertEquals("Nacos.client.naming.worker / subscriberDeregister", spanData.getName()); + + Assert.assertEquals(serviceName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.SERVICE_NAME))); + Assert.assertEquals(groupName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.GROUP))); + Assert.assertEquals(clusterName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.CLUSTER))); + } + + @Test + public void testIsSubscriberRegistered() { + delegate.isSubscriberRegistered(serviceName, groupName, clusterName); + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + SpanData spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1); + Assert.assertEquals("Nacos.client.naming.worker / isSubscriberRegistered", spanData.getName()); + + Assert.assertEquals(serviceName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.SERVICE_NAME))); + Assert.assertEquals(groupName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.GROUP))); + Assert.assertEquals(clusterName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.CLUSTER))); + } + + @Test + public void testRemoveSubscriberForRedo() { + delegate.removeSubscriberForRedo(serviceName, groupName, clusterName); + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + SpanData spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1); + Assert.assertEquals("Nacos.client.naming.worker / removeSubscriberForRedo", spanData.getName()); + + Assert.assertEquals(serviceName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.SERVICE_NAME))); + Assert.assertEquals(groupName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.GROUP))); + Assert.assertEquals(clusterName, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.CLUSTER))); + } + + @Test + public void testGetRegisteredInstancesByKey() { + String combineKey = NamingUtils.getGroupedName(serviceName, groupName); + + delegate.getRegisteredInstancesByKey(combineKey); + Assert.assertFalse(testExporter.exportedSpans.isEmpty()); + SpanData spanData = testExporter.exportedSpans.get(testExporter.exportedSpans.size() - 1); + Assert.assertEquals("Nacos.client.naming.worker / getRegisteredInstancesByKey", spanData.getName()); + + Assert.assertEquals(combineKey, + spanData.getAttributes().get(AttributeKey.stringKey(NacosSemanticAttributes.SERVICE_NAME))); + } +} From d03a43b2e8c43cf843cfe8636b00acf704fe9abe Mon Sep 17 00:00:00 2001 From: FAWC438 Date: Tue, 26 Dec 2023 16:40:50 +0800 Subject: [PATCH 5/5] Fix pmd issues --- .../config/ConfigRpcTransportClientProxy.java | 1 + .../naming/NamingClientProxyTraceDelegate.java | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ConfigRpcTransportClientProxy.java b/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ConfigRpcTransportClientProxy.java index c244a062737..70e8bbff0f5 100644 --- a/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ConfigRpcTransportClientProxy.java +++ b/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/config/ConfigRpcTransportClientProxy.java @@ -87,6 +87,7 @@ boolean publishConfig(String dataId, String group, String tenant, String appName * @param rpcClientInner rpcClientInner * @param request request * @param timeoutMills timeoutMills + * @return Response * @throws NacosException NacosException */ Response rpcRequest(RpcClient rpcClientInner, Request request, long timeoutMills) throws NacosException; diff --git a/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/naming/NamingClientProxyTraceDelegate.java b/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/naming/NamingClientProxyTraceDelegate.java index 8feb1014679..92ab6817113 100644 --- a/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/naming/NamingClientProxyTraceDelegate.java +++ b/client/src/main/java/com/alibaba/nacos/client/monitor/delegate/naming/NamingClientProxyTraceDelegate.java @@ -50,6 +50,10 @@ public class NamingClientProxyTraceDelegate implements NamingClientProxy { private final String namingClientType; + private final String grpcType = "grpc"; + + private final String httpType = "http"; + /** * Constructor with a naming client proxy. This class will delegate all method for Opentelemetry trace. * @@ -75,7 +79,8 @@ public NamingClientProxyTraceDelegate(NamingClientProxy namingClientProxyImpl) { */ private SpanBuilder initSpanBuilder(String methodName) { SpanBuilder spanBuilder; - if (namingClientType.equals("grpc") || namingClientType.equals("http")) { + + if (namingClientType.equals(grpcType) || namingClientType.equals(httpType)) { spanBuilder = NamingTrace.getClientNamingWorkerSpanBuilder(methodName); } else { spanBuilder = NamingTrace.getClientNamingServiceSpanBuilder(methodName); @@ -422,9 +427,9 @@ public ListView getServiceList(int pageNo, int pageSize, String groupNam try (Scope ignored = span.makeCurrent()) { if (span.isRecording()) { - if (namingClientType.equals("grpc")) { + if (namingClientType.equals(grpcType)) { span.setAttribute(SemanticAttributes.RPC_SYSTEM, "grpc"); - } else if (namingClientType.equals("http")) { + } else if (namingClientType.equals(httpType)) { span.setAttribute(SemanticAttributes.HTTP_METHOD, HttpMethod.GET); } span.setAttribute(NacosSemanticAttributes.PAGE_NO, pageNo);