From a2c56636f1afc441ad564499123db0aed9f1eede Mon Sep 17 00:00:00 2001 From: hanbingleixue Date: Thu, 31 Oct 2024 12:51:33 +0800 Subject: [PATCH] Add metric collection function in router plugin Signed-off-by: hanbingleixue --- .../implement/service/metric/MeterMetric.java | 2 +- .../sermant-router/config/config.yaml | 2 + .../dubbo-router-plugin/pom.xml | 2 +- .../AlibabaDubboMonitorFilterDeclarer.java | 57 +++++++ .../ApacheDubboMonitorFilterDeclarer.java | 57 +++++++ .../handler/LaneContextFilterHandler.java | 20 +++ .../AlibabaDubboMonitorFilterInterceptor.java | 69 ++++++++ .../ApacheDubboMonitorFilterInterceptor.java | 69 ++++++++ ....core.plugin.agent.declarer.PluginDeclarer | 2 + .../handler/LaneContextFilterHandlerTest.java | 8 + .../router/common}/cache/AppCache.java | 2 +- .../router/common/config/RouterConfig.java | 14 ++ .../common/constants/RouterConstant.java | 90 +++++++++++ .../router/common/metric/MetricInfo.java | 87 ++++++++++ .../common/metric/MetricThreadLocal.java | 58 +++++++ .../router/common/metric/MetricsManager.java | 151 ++++++++++++++++++ .../router/common/xds/XdsRouterHandler.java | 15 ++ .../config/strategy/AbstractRuleStrategy.java | 63 ++++++++ .../spring/handler/AbstractHandler.java | 36 +++++ .../spring/handler/LaneMappingHandler.java | 1 + .../spring/handler/LaneRequestTagHandler.java | 1 + .../ClientHttpRequestInterceptor.java | 20 +++ .../DiscoveryManagerInterceptor.java | 2 +- .../EurekaHttpClientInterceptor.java | 2 +- .../interceptor/FeignClientInterceptor.java | 29 ++++ .../HttpAsyncClient4xInterceptor.java | 32 +++- .../interceptor/HttpClient4xInterceptor.java | 23 ++- .../HttpUrlConnectionConnectInterceptor.java | 17 +- .../interceptor/OkHttp3ClientInterceptor.java | 23 ++- ...HttpClientInterceptorChainInterceptor.java | 31 +++- .../interceptor/RestTemplateInterceptor.java | 20 ++- .../ServiceRegistryInterceptor.java | 2 +- .../spring/utils/SpringRouterUtils.java | 2 +- .../router/spring/BaseTransmitConfigTest.java | 3 + .../handler/LaneMappingHandlerTest.java | 9 ++ .../handler/LaneRequestTagHandlerTest.java | 8 + .../DiscoveryManagerInterceptorTest.java | 2 +- .../EurekaHttpClientInterceptorTest.java | 2 +- .../FeignClientInterceptorTest.java | 2 + .../ServiceRegistryInterceptorTest.java | 2 +- .../spring/handler/FlowRouteHandler.java | 2 +- .../spring/handler/TagRouteHandler.java | 2 +- .../spring/service/LaneServiceImpl.java | 2 +- .../spring/RuleInitializationUtils.java | 2 +- .../spring/handler/TagRouteHandlerTest.java | 2 +- .../spring/service/LaneServiceTest.java | 2 +- .../service/LoadBalancerServiceTest.java | 2 +- 47 files changed, 1016 insertions(+), 35 deletions(-) create mode 100644 sermant-plugins/sermant-router/dubbo-router-plugin/src/main/java/io/sermant/router/dubbo/declarer/AlibabaDubboMonitorFilterDeclarer.java create mode 100644 sermant-plugins/sermant-router/dubbo-router-plugin/src/main/java/io/sermant/router/dubbo/declarer/ApacheDubboMonitorFilterDeclarer.java create mode 100644 sermant-plugins/sermant-router/dubbo-router-plugin/src/main/java/io/sermant/router/dubbo/interceptor/AlibabaDubboMonitorFilterInterceptor.java create mode 100644 sermant-plugins/sermant-router/dubbo-router-plugin/src/main/java/io/sermant/router/dubbo/interceptor/ApacheDubboMonitorFilterInterceptor.java rename sermant-plugins/sermant-router/{spring-router-plugin/src/main/java/io/sermant/router/spring => router-common/src/main/java/io/sermant/router/common}/cache/AppCache.java (96%) create mode 100644 sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/metric/MetricInfo.java create mode 100644 sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/metric/MetricThreadLocal.java create mode 100644 sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/metric/MetricsManager.java diff --git a/sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/metric/MeterMetric.java b/sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/metric/MeterMetric.java index f6870d1a07..90ca783e13 100644 --- a/sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/metric/MeterMetric.java +++ b/sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/metric/MeterMetric.java @@ -138,7 +138,7 @@ private Iterable getMeterTags(Tags tags) { for (Map.Entry entry : tags.getTags().entrySet()) { String key = entry.getKey(); String value = entry.getValue(); - if (StringUtils.isEmpty(key) || StringUtils.isEmpty(value)) { + if (StringUtils.isEmpty(key) || value == null) { continue; } result.add(Tag.of(entry.getKey(), value)); diff --git a/sermant-plugins/sermant-router/config/config.yaml b/sermant-plugins/sermant-router/config/config.yaml index 22d028fdf3..f3114ac1d9 100644 --- a/sermant-plugins/sermant-router/config/config.yaml +++ b/sermant-plugins/sermant-router/config/config.yaml @@ -19,6 +19,8 @@ router.plugin: enabled-spring-zone-router: false # compatibility router config 1.0, default is false not support enabled-previous-rule: false + # Whether to Enable Metrics Collection + enable-metric: false transmit.plugin: # Whether to transmit the label on the direct new thread enabled-thread: true diff --git a/sermant-plugins/sermant-router/dubbo-router-plugin/pom.xml b/sermant-plugins/sermant-router/dubbo-router-plugin/pom.xml index 8958a4c162..4ec3d65051 100644 --- a/sermant-plugins/sermant-router/dubbo-router-plugin/pom.xml +++ b/sermant-plugins/sermant-router/dubbo-router-plugin/pom.xml @@ -36,7 +36,7 @@ org.apache.dubbo dubbo-config-api ${dubbo.version} - test + provided com.alibaba diff --git a/sermant-plugins/sermant-router/dubbo-router-plugin/src/main/java/io/sermant/router/dubbo/declarer/AlibabaDubboMonitorFilterDeclarer.java b/sermant-plugins/sermant-router/dubbo-router-plugin/src/main/java/io/sermant/router/dubbo/declarer/AlibabaDubboMonitorFilterDeclarer.java new file mode 100644 index 0000000000..ecace3cae0 --- /dev/null +++ b/sermant-plugins/sermant-router/dubbo-router-plugin/src/main/java/io/sermant/router/dubbo/declarer/AlibabaDubboMonitorFilterDeclarer.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2024-2024 Sermant Authors. All rights reserved. + * + * 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 io.sermant.router.dubbo.declarer; + +import io.sermant.core.plugin.agent.declarer.AbstractPluginDeclarer; +import io.sermant.core.plugin.agent.declarer.InterceptDeclarer; +import io.sermant.core.plugin.agent.matcher.ClassMatcher; +import io.sermant.core.plugin.agent.matcher.MethodMatcher; +import io.sermant.core.plugin.config.PluginConfigManager; +import io.sermant.router.common.config.RouterConfig; +import io.sermant.router.dubbo.interceptor.AlibabaDubboMonitorFilterInterceptor; + +/** + * Enhanced Declarer of the MonitorFilter + * + * @author zhp + * @since 2024-10-23 + */ +public class AlibabaDubboMonitorFilterDeclarer extends AbstractPluginDeclarer { + private static final String ENHANCE_CLASS = "com.alibaba.dubbo.monitor.support.MonitorFilter"; + + private static final String METHOD_NAME = "invoke"; + + private static final RouterConfig ROUTER_CONFIG = PluginConfigManager.getPluginConfig(RouterConfig.class); + + @Override + public ClassMatcher getClassMatcher() { + return ClassMatcher.nameEquals(ENHANCE_CLASS); + } + + @Override + public InterceptDeclarer[] getInterceptDeclarers(ClassLoader classLoader) { + return new InterceptDeclarer[]{ + InterceptDeclarer.build(MethodMatcher.nameEquals(METHOD_NAME), + new AlibabaDubboMonitorFilterInterceptor()) + }; + } + + @Override + public boolean isEnabled() { + return ROUTER_CONFIG.isEnableMetric(); + } +} diff --git a/sermant-plugins/sermant-router/dubbo-router-plugin/src/main/java/io/sermant/router/dubbo/declarer/ApacheDubboMonitorFilterDeclarer.java b/sermant-plugins/sermant-router/dubbo-router-plugin/src/main/java/io/sermant/router/dubbo/declarer/ApacheDubboMonitorFilterDeclarer.java new file mode 100644 index 0000000000..294b267aa6 --- /dev/null +++ b/sermant-plugins/sermant-router/dubbo-router-plugin/src/main/java/io/sermant/router/dubbo/declarer/ApacheDubboMonitorFilterDeclarer.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2024-2024 Sermant Authors. All rights reserved. + * + * 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 io.sermant.router.dubbo.declarer; + +import io.sermant.core.plugin.agent.declarer.AbstractPluginDeclarer; +import io.sermant.core.plugin.agent.declarer.InterceptDeclarer; +import io.sermant.core.plugin.agent.matcher.ClassMatcher; +import io.sermant.core.plugin.agent.matcher.MethodMatcher; +import io.sermant.core.plugin.config.PluginConfigManager; +import io.sermant.router.common.config.RouterConfig; +import io.sermant.router.dubbo.interceptor.ApacheDubboMonitorFilterInterceptor; + +/** + * Enhanced Declarer of the MonitorFilter + * + * @author zhp + * @since 2024-10-23 + */ +public class ApacheDubboMonitorFilterDeclarer extends AbstractPluginDeclarer { + private static final String ENHANCE_CLASS = "org.apache.dubbo.monitor.support.MonitorFilter"; + + private static final String METHOD_NAME = "invoke"; + + private static final RouterConfig ROUTER_CONFIG = PluginConfigManager.getPluginConfig(RouterConfig.class); + + @Override + public ClassMatcher getClassMatcher() { + return ClassMatcher.nameEquals(ENHANCE_CLASS); + } + + @Override + public InterceptDeclarer[] getInterceptDeclarers(ClassLoader classLoader) { + return new InterceptDeclarer[]{ + InterceptDeclarer.build(MethodMatcher.nameEquals(METHOD_NAME), + new ApacheDubboMonitorFilterInterceptor()) + }; + } + + @Override + public boolean isEnabled() { + return ROUTER_CONFIG.isEnableMetric(); + } +} diff --git a/sermant-plugins/sermant-router/dubbo-router-plugin/src/main/java/io/sermant/router/dubbo/handler/LaneContextFilterHandler.java b/sermant-plugins/sermant-router/dubbo-router-plugin/src/main/java/io/sermant/router/dubbo/handler/LaneContextFilterHandler.java index aac6091383..df5c9ca420 100644 --- a/sermant-plugins/sermant-router/dubbo-router-plugin/src/main/java/io/sermant/router/dubbo/handler/LaneContextFilterHandler.java +++ b/sermant-plugins/sermant-router/dubbo-router-plugin/src/main/java/io/sermant/router/dubbo/handler/LaneContextFilterHandler.java @@ -17,13 +17,18 @@ package io.sermant.router.dubbo.handler; import io.sermant.core.common.LoggerFactory; +import io.sermant.core.plugin.config.PluginConfigManager; import io.sermant.core.plugin.service.PluginServiceManager; +import io.sermant.router.common.cache.DubboCache; +import io.sermant.router.common.config.RouterConfig; import io.sermant.router.common.constants.RouterConstant; +import io.sermant.router.common.metric.MetricsManager; import io.sermant.router.common.utils.CollectionUtils; import io.sermant.router.common.utils.DubboReflectUtils; import io.sermant.router.dubbo.service.LaneContextFilterService; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -39,6 +44,8 @@ public class LaneContextFilterHandler extends AbstractContextFilterHandler { private static final Logger LOGGER = LoggerFactory.getLogger(); + private final RouterConfig routerConfig = PluginConfigManager.getPluginConfig(RouterConfig.class); + private final LaneContextFilterService laneContextFilterService; /** @@ -77,6 +84,19 @@ public Map> getRequestTag(Object invoker, Object invocation if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine("Lane is " + requestTag); } + if (!routerConfig.isEnableMetric()) { + return requestTag; + } + laneTag.forEach((key, values) -> { + if (CollectionUtils.isEmpty(values)) { + return; + } + Map tagsMap = new HashMap<>(); + tagsMap.put(RouterConstant.CLIENT_SERVICE_NAME, DubboCache.INSTANCE.getAppName()); + tagsMap.put(key, values.get(0)); + tagsMap.put(RouterConstant.PROTOCOL, RouterConstant.DUBBO_PROTOCOL); + MetricsManager.addOrUpdateCounterMetricValue(RouterConstant.LANE_TAG_COUNT, tagsMap, 1); + }); return requestTag; } diff --git a/sermant-plugins/sermant-router/dubbo-router-plugin/src/main/java/io/sermant/router/dubbo/interceptor/AlibabaDubboMonitorFilterInterceptor.java b/sermant-plugins/sermant-router/dubbo-router-plugin/src/main/java/io/sermant/router/dubbo/interceptor/AlibabaDubboMonitorFilterInterceptor.java new file mode 100644 index 0000000000..a0faf39511 --- /dev/null +++ b/sermant-plugins/sermant-router/dubbo-router-plugin/src/main/java/io/sermant/router/dubbo/interceptor/AlibabaDubboMonitorFilterInterceptor.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2024-2024 Sermant Authors. All rights reserved. + * + * 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 io.sermant.router.dubbo.interceptor; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Invoker; + +import io.sermant.core.plugin.agent.entity.ExecuteContext; +import io.sermant.core.plugin.agent.interceptor.AbstractInterceptor; +import io.sermant.router.common.cache.DubboCache; +import io.sermant.router.common.constants.RouterConstant; +import io.sermant.router.common.metric.MetricsManager; + +import java.util.HashMap; +import java.util.Map; + +/** + * Interceptor of the MonitorFilter, Collecting Metric Information + * + * @author zhp + * @since 2024-10-23 + */ +public class AlibabaDubboMonitorFilterInterceptor extends AbstractInterceptor { + @Override + public ExecuteContext before(ExecuteContext context) throws Exception { + return context; + } + + @Override + public ExecuteContext after(ExecuteContext context) throws Exception { + Object[] arguments = context.getArguments(); + if (arguments == null || arguments.length == 0) { + return context; + } + if (!(arguments[0] instanceof Invoker)) { + return context; + } + Invoker invoker = (Invoker) arguments[0]; + URL url = invoker.getUrl(); + if (isConsumer(url)) { + String address = url.getHost() + RouterConstant.URL_CONNECTOR + url.getPort(); + Map tagsMap = new HashMap<>(); + tagsMap.put(RouterConstant.SERVER_ADDRESS, address); + tagsMap.put(RouterConstant.CLIENT_SERVICE_NAME, DubboCache.INSTANCE.getAppName()); + tagsMap.put(RouterConstant.PROTOCOL, RouterConstant.DUBBO_PROTOCOL); + MetricsManager.addOrUpdateCounterMetricValue(RouterConstant.ROUTER_REQUEST_COUNT, tagsMap, 1); + } + return context; + } + + private boolean isConsumer(URL url) { + return RouterConstant.DUBBO_CONSUMER.equals(url.getParameter(RouterConstant.DUBBO_SIDE, + RouterConstant.DUBBO_PROVIDER)); + } +} diff --git a/sermant-plugins/sermant-router/dubbo-router-plugin/src/main/java/io/sermant/router/dubbo/interceptor/ApacheDubboMonitorFilterInterceptor.java b/sermant-plugins/sermant-router/dubbo-router-plugin/src/main/java/io/sermant/router/dubbo/interceptor/ApacheDubboMonitorFilterInterceptor.java new file mode 100644 index 0000000000..6c7a56c102 --- /dev/null +++ b/sermant-plugins/sermant-router/dubbo-router-plugin/src/main/java/io/sermant/router/dubbo/interceptor/ApacheDubboMonitorFilterInterceptor.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2024-2024 Sermant Authors. All rights reserved. + * + * 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 io.sermant.router.dubbo.interceptor; + +import io.sermant.core.plugin.agent.entity.ExecuteContext; +import io.sermant.core.plugin.agent.interceptor.AbstractInterceptor; +import io.sermant.router.common.cache.DubboCache; +import io.sermant.router.common.constants.RouterConstant; +import io.sermant.router.common.metric.MetricsManager; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.rpc.Invoker; + +import java.util.HashMap; +import java.util.Map; + +/** + * Interceptor of the MonitorFilter, Collecting Metric Information + * + * @author zhp + * @since 2024-10-23 + */ +public class ApacheDubboMonitorFilterInterceptor extends AbstractInterceptor { + @Override + public ExecuteContext before(ExecuteContext context) throws Exception { + return context; + } + + @Override + public ExecuteContext after(ExecuteContext context) throws Exception { + Object[] arguments = context.getArguments(); + if (arguments == null || arguments.length == 0) { + return context; + } + if (!(arguments[0] instanceof Invoker)) { + return context; + } + Invoker invoker = (Invoker) arguments[0]; + URL url = invoker.getUrl(); + if (isConsumer(url)) { + String address = url.getHost() + RouterConstant.URL_CONNECTOR + url.getPort(); + Map tagsMap = new HashMap<>(); + tagsMap.put(RouterConstant.SERVER_ADDRESS, address); + tagsMap.put(RouterConstant.CLIENT_SERVICE_NAME, DubboCache.INSTANCE.getAppName()); + tagsMap.put(RouterConstant.PROTOCOL, RouterConstant.DUBBO_PROTOCOL); + MetricsManager.addOrUpdateCounterMetricValue(RouterConstant.ROUTER_REQUEST_COUNT, tagsMap, 1); + } + return context; + } + + private boolean isConsumer(URL url) { + return RouterConstant.DUBBO_CONSUMER.equals(url.getParameter(RouterConstant.DUBBO_SIDE, + RouterConstant.DUBBO_PROVIDER)); + } +} diff --git a/sermant-plugins/sermant-router/dubbo-router-plugin/src/main/resources/META-INF/services/io.sermant.core.plugin.agent.declarer.PluginDeclarer b/sermant-plugins/sermant-router/dubbo-router-plugin/src/main/resources/META-INF/services/io.sermant.core.plugin.agent.declarer.PluginDeclarer index 9ad32b1758..da5a65269e 100644 --- a/sermant-plugins/sermant-router/dubbo-router-plugin/src/main/resources/META-INF/services/io.sermant.core.plugin.agent.declarer.PluginDeclarer +++ b/sermant-plugins/sermant-router/dubbo-router-plugin/src/main/resources/META-INF/services/io.sermant.core.plugin.agent.declarer.PluginDeclarer @@ -8,3 +8,5 @@ io.sermant.router.dubbo.declarer.ClusterUtilsDeclarer io.sermant.router.dubbo.declarer.ContextFilterDeclarer io.sermant.router.dubbo.declarer.SpringApplicationDeclarer io.sermant.router.dubbo.declarer.AbstractConfigDeclarer +io.sermant.router.dubbo.declarer.ApacheDubboMonitorFilterDeclarer +io.sermant.router.dubbo.declarer.AlibabaDubboMonitorFilterDeclarer diff --git a/sermant-plugins/sermant-router/dubbo-router-plugin/src/test/java/io/sermant/router/dubbo/handler/LaneContextFilterHandlerTest.java b/sermant-plugins/sermant-router/dubbo-router-plugin/src/test/java/io/sermant/router/dubbo/handler/LaneContextFilterHandlerTest.java index c6143a5b6d..be1a9d1e3d 100644 --- a/sermant-plugins/sermant-router/dubbo-router-plugin/src/test/java/io/sermant/router/dubbo/handler/LaneContextFilterHandlerTest.java +++ b/sermant-plugins/sermant-router/dubbo-router-plugin/src/test/java/io/sermant/router/dubbo/handler/LaneContextFilterHandlerTest.java @@ -16,7 +16,9 @@ package io.sermant.router.dubbo.handler; +import io.sermant.core.plugin.config.PluginConfigManager; import io.sermant.core.service.ServiceManager; +import io.sermant.router.common.config.RouterConfig; import io.sermant.router.dubbo.TestDubboConfigService; import io.sermant.router.dubbo.service.LaneContextFilterService; @@ -44,6 +46,8 @@ public class LaneContextFilterHandlerTest { private static MockedStatic mockServiceManager; + private static MockedStatic mockPluginConfigManager; + private final LaneContextFilterHandler laneContextFilterHandler; private final TestDubboConfigService configService; @@ -63,6 +67,9 @@ public static void before() { mockServiceManager = Mockito.mockStatic(ServiceManager.class); mockServiceManager.when(() -> ServiceManager.getService(LaneContextFilterService.class)) .thenReturn(LANE_CONTEXT_FILTER_SERVICE); + mockPluginConfigManager = Mockito.mockStatic(PluginConfigManager.class); + mockPluginConfigManager.when(()-> PluginConfigManager.getPluginConfig(RouterConfig.class)) + .thenReturn(new RouterConfig()); } /** @@ -71,6 +78,7 @@ public static void before() { @AfterClass public static void after() { mockServiceManager.close(); + mockPluginConfigManager.close(); } public LaneContextFilterHandlerTest() { diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/cache/AppCache.java b/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/cache/AppCache.java similarity index 96% rename from sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/cache/AppCache.java rename to sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/cache/AppCache.java index 0aac36de5c..09e0026087 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/cache/AppCache.java +++ b/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/cache/AppCache.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.sermant.router.spring.cache; +package io.sermant.router.common.cache; import java.util.Map; diff --git a/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/config/RouterConfig.java b/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/config/RouterConfig.java index c03e45ad84..7074430330 100644 --- a/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/config/RouterConfig.java +++ b/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/config/RouterConfig.java @@ -107,6 +107,12 @@ public class RouterConfig implements PluginConfig { @ConfigFieldKey("enabled-previous-rule") private boolean enabledPreviousRule = false; + /** + * Whether to Enable Metrics Collection + */ + @ConfigFieldKey("enable-metric") + private boolean enableMetric = false; + /** * Constructor */ @@ -225,4 +231,12 @@ public boolean isEnabledSpringCloudXdsRouteSecure() { public void setEnabledSpringCloudXdsRouteSecure(boolean enabledSpringCloudXdsRouteSecure) { this.enabledSpringCloudXdsRouteSecure = enabledSpringCloudXdsRouteSecure; } + + public boolean isEnableMetric() { + return enableMetric; + } + + public void setEnableMetric(boolean enableMetric) { + this.enableMetric = enableMetric; + } } diff --git a/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/constants/RouterConstant.java b/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/constants/RouterConstant.java index f180b2e8ce..b5e3b56243 100644 --- a/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/constants/RouterConstant.java +++ b/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/constants/RouterConstant.java @@ -193,6 +193,96 @@ public class RouterConstant { */ public static final String ESCAPED_POINT = "\\."; + /** + * Metric Name for Router Request Count + */ + public static final String ROUTER_REQUEST_COUNT = "router_request_count"; + + /** + * Metric Name for matched routing tag Count + */ + public static final String ROUTER_DESTINATION_TAG_COUNT = "router_destination_tag_count"; + + /** + * Metric Name for unmatched routing request Count + */ + public static final String ROUTER_UNMATCHED_REQUEST_COUNT = "router_unmatched_request_count"; + + /** + * Metric Name for lane Count + */ + public static final String LANE_TAG_COUNT = "lane_tag_count"; + + /** + * the name for the server address tag + */ + public static final String SERVER_ADDRESS = "server_address"; + + /** + * the name for the protocol tag + */ + public static final String PROTOCOL = "protocol"; + + /** + * the name for the client service name tag + */ + public static final String CLIENT_SERVICE_NAME = "client_service_name"; + + /** + * the name for the lane tag + */ + public static final String LANE_TAG = "lane_tag"; + + /** + * Scope for metrics + */ + public static final String SCOPE = "scope"; + + /** + * the name for the service.meta.parameters tag + */ + public static final String SERVICE_META_PARAMETERS = "service_meta_parameters"; + + /** + * URL Connector + */ + public static final String URL_CONNECTOR = ":"; + + /** + * dubbo consumer + */ + public static final String DUBBO_CONSUMER = "consumer"; + + /** + * dubbo provider + */ + public static final String DUBBO_PROVIDER = "provider"; + + /** + * distinguish between dubbo callers: provider or consumer + */ + public static final String DUBBO_SIDE = "side"; + + /** + * Flag indicating if it has been executed + */ + public static final String EXECUTE_FLAG = "executeFlag"; + + /** + * HTTP protocol + */ + public static final String HTTP_PROTOCOL = "http"; + + /** + * Dubbo protocol + */ + public static final String DUBBO_PROTOCOL = "dubbo"; + + /** + * XDS protocol + */ + public static final String XDS_PROTOCOL = "xds"; + private RouterConstant() { } } diff --git a/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/metric/MetricInfo.java b/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/metric/MetricInfo.java new file mode 100644 index 0000000000..00b9b21a2e --- /dev/null +++ b/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/metric/MetricInfo.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2024-2024 Sermant Authors. All rights reserved. + * + * 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 io.sermant.router.common.metric; + +import io.sermant.core.utils.StringUtils; + +import java.util.Map; +import java.util.Objects; + +/** + * Routing Metrics information + * + * @author zhp + * @since 2024-10-16 + */ +public class MetricInfo { + /** + * Metric Name + */ + private String metricName; + + /** + * Tag Information + */ + private Map tags; + + /** + * Constructor + * + * @param metricName metric name + * @param tags tag information + */ + public MetricInfo(String metricName, Map tags) { + this.metricName = metricName; + this.tags = tags; + } + + @Override + public int hashCode() { + return Objects.hash(metricName, tags); + } + + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (object == null || getClass() != object.getClass()) { + return false; + } + MetricInfo metricInfo = (MetricInfo) object; + if (!StringUtils.equals(this.metricName, metricInfo.getMetricName())) { + return false; + } + return Objects.equals(this.tags, metricInfo.getTags()); + } + + public String getMetricName() { + return metricName; + } + + public void setMetricName(String metricName) { + this.metricName = metricName; + } + + public Map getTags() { + return tags; + } + + public void setTags(Map tags) { + this.tags = tags; + } +} diff --git a/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/metric/MetricThreadLocal.java b/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/metric/MetricThreadLocal.java new file mode 100644 index 0000000000..83e86fc489 --- /dev/null +++ b/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/metric/MetricThreadLocal.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2024-2024 Sermant Authors. All rights reserved. + * + * 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 io.sermant.router.common.metric; + +/** + * Thread-local variables, Store the flag for metric collection to prevent duplicate collection + * + * @author zhp + * @since 2024-10-16 + */ +public class MetricThreadLocal { + private static final ThreadLocal FLAG = new ThreadLocal<>(); + + /** + * Constructor + */ + private MetricThreadLocal() { + } + + /** + * Set flag information + * + * @param flag execute flag + */ + public static void setFlag(Boolean flag) { + FLAG.set(flag); + } + + /** + * Get flag information + * + * @return flag information + */ + public static boolean getFlag() { + return FLAG.get() != null && FLAG.get(); + } + + /** + * remove flag information + */ + public static void removeFlag() { + FLAG.remove(); + } +} diff --git a/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/metric/MetricsManager.java b/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/metric/MetricsManager.java new file mode 100644 index 0000000000..3024bed093 --- /dev/null +++ b/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/metric/MetricsManager.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2024-2024 Sermant Authors. All rights reserved. + * + * 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 io.sermant.router.common.metric; + +import io.sermant.core.common.LoggerFactory; +import io.sermant.core.plugin.config.PluginConfigManager; +import io.sermant.core.service.ServiceManager; +import io.sermant.core.service.metric.api.Counter; +import io.sermant.core.service.metric.api.MetricService; +import io.sermant.core.service.metric.api.Tags; +import io.sermant.core.utils.StringUtils; +import io.sermant.router.common.cache.AppCache; +import io.sermant.router.common.cache.DubboCache; +import io.sermant.router.common.config.RouterConfig; +import io.sermant.router.common.constants.RouterConstant; + +import java.net.URI; +import java.net.URL; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Routing Metrics Management Class + * + * @author zhp + * @since 2024-10-16 + */ +public class MetricsManager { + private static final Logger LOGGER = LoggerFactory.getLogger(); + + private static final Map COUNT_MAP = new ConcurrentHashMap<>(); + + private static final RouterConfig ROUTER_CONFIG = PluginConfigManager.getPluginConfig(RouterConfig.class); + + private static final Map TAG_KEY_MAP = new ConcurrentHashMap<>(); + + private static MetricService metricService = null; + + static { + try { + metricService = ServiceManager.getService(MetricService.class); + TAG_KEY_MAP.put("service","service_meta_service"); + TAG_KEY_MAP.put("version","service_meta_version"); + TAG_KEY_MAP.put("application","service_meta_application"); + TAG_KEY_MAP.put("zone","service_meta_zone"); + TAG_KEY_MAP.put("project","service_meta_project"); + TAG_KEY_MAP.put("environment","service_meta_environment"); + TAG_KEY_MAP.put("parameters","service_meta_parameters"); + } catch (IllegalArgumentException e) { + LOGGER.log(Level.SEVERE, "Failed to load metrics service", e); + } + } + + /** + * Constructor + */ + private MetricsManager() { + } + + /** + * Add or update the value of the metric. + * + * @param metricName metric Name + * @param tags tag information + * @param value count add value + */ + public static void addOrUpdateCounterMetricValue(String metricName, Map tags, double value) { + if (metricService == null || !ROUTER_CONFIG.isEnableMetric()) { + return; + } + Map tagsMap; + if (tags != null) { + tagsMap = new HashMap<>(tags); + } else { + tagsMap = new HashMap<>(); + } + tagsMap.put(RouterConstant.SCOPE,"service-router"); + Counter counter = COUNT_MAP.computeIfAbsent(new MetricInfo(metricName, tagsMap), + metricInfo -> metricService.counter(metricName, Tags.of(tagsMap))); + counter.increment(value); + } + + /** + * Collect request count metric information + * + * @param url url information + */ + public static void collectRequestCountMetric(URL url) { + String address = url.getHost() + RouterConstant.URL_CONNECTOR + url.getPort(); + collectRequestCountMetric(address); + } + + /** + * Collect request count metric information + * + * @param uri uri information + */ + public static void collectRequestCountMetric(URI uri) { + String address = uri.getHost() + RouterConstant.URL_CONNECTOR + uri.getPort(); + collectRequestCountMetric(address); + } + + private static void collectRequestCountMetric(String address) { + Map tagsMap = new HashMap<>(); + if (StringUtils.isEmpty(DubboCache.INSTANCE.getAppName())) { + tagsMap.put(RouterConstant.CLIENT_SERVICE_NAME, AppCache.INSTANCE.getAppName()); + } else { + tagsMap.put(RouterConstant.CLIENT_SERVICE_NAME, DubboCache.INSTANCE.getAppName()); + } + tagsMap.put(RouterConstant.SERVER_ADDRESS, address); + tagsMap.put(RouterConstant.PROTOCOL, RouterConstant.HTTP_PROTOCOL); + addOrUpdateCounterMetricValue(RouterConstant.ROUTER_REQUEST_COUNT, tagsMap, 1); + } + + /** + * Get the key of the metric tag + * + * @param tagName tag name for routing rules or lane rules + * @return the key of the metric tag + */ + public static String getTagKeyByRouteTagOrLaneTag(String tagName) { + return TAG_KEY_MAP.get(tagName); + } + + /** + * Get All the key of the metric tag + * + * @return All the key of the metric tag + */ + public static Collection getAllTagKey() { + return TAG_KEY_MAP.values(); + } +} diff --git a/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/xds/XdsRouterHandler.java b/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/xds/XdsRouterHandler.java index eb5dbdffe4..2795aee114 100644 --- a/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/xds/XdsRouterHandler.java +++ b/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/xds/XdsRouterHandler.java @@ -33,9 +33,14 @@ import io.sermant.core.service.xds.entity.XdsRouteMatch; import io.sermant.core.utils.CollectionUtils; import io.sermant.core.utils.StringUtils; +import io.sermant.router.common.cache.AppCache; +import io.sermant.router.common.cache.DubboCache; +import io.sermant.router.common.constants.RouterConstant; +import io.sermant.router.common.metric.MetricsManager; import io.sermant.router.common.utils.XdsRouterUtils; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -148,6 +153,16 @@ private Set handleXdsRoute(XdsRoute route, String serviceName) if (routeAction.isWeighted()) { cluster = selectClusterByWeight(routeAction.getWeightedClusters()); } + Map tagsMap = new HashMap<>(); + MetricsManager.getAllTagKey().forEach(key -> tagsMap.put(key, StringUtils.EMPTY)); + tagsMap.put(RouterConstant.SERVICE_META_PARAMETERS, "cluster: " + cluster); + if (StringUtils.isEmpty(DubboCache.INSTANCE.getAppName())) { + tagsMap.put(RouterConstant.CLIENT_SERVICE_NAME, AppCache.INSTANCE.getAppName()); + } else { + tagsMap.put(RouterConstant.CLIENT_SERVICE_NAME, DubboCache.INSTANCE.getAppName()); + } + tagsMap.put(RouterConstant.PROTOCOL, RouterConstant.XDS_PROTOCOL); + MetricsManager.addOrUpdateCounterMetricValue(RouterConstant.ROUTER_DESTINATION_TAG_COUNT, tagsMap, 1); // get service instance of cluster Optional loadAssigmentOptional = diff --git a/sermant-plugins/sermant-router/router-config-common/src/main/java/io/sermant/router/config/strategy/AbstractRuleStrategy.java b/sermant-plugins/sermant-router/router-config-common/src/main/java/io/sermant/router/config/strategy/AbstractRuleStrategy.java index 596c561857..2095c7068b 100644 --- a/sermant-plugins/sermant-router/router-config-common/src/main/java/io/sermant/router/config/strategy/AbstractRuleStrategy.java +++ b/sermant-plugins/sermant-router/router-config-common/src/main/java/io/sermant/router/config/strategy/AbstractRuleStrategy.java @@ -19,7 +19,14 @@ import com.alibaba.fastjson.JSONObject; import io.sermant.core.common.LoggerFactory; +import io.sermant.core.plugin.config.PluginConfigManager; +import io.sermant.core.utils.StringUtils; +import io.sermant.router.common.cache.AppCache; +import io.sermant.router.common.cache.DubboCache; +import io.sermant.router.common.config.RouterConfig; +import io.sermant.router.common.constants.RouterConstant; import io.sermant.router.common.event.PolicyEvent; +import io.sermant.router.common.metric.MetricsManager; import io.sermant.router.common.utils.CollectionUtils; import io.sermant.router.config.entity.Match; import io.sermant.router.config.entity.Policy; @@ -30,6 +37,7 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; @@ -47,6 +55,8 @@ public abstract class AbstractRuleStrategy implements RuleStrategy { private static final Logger LOGGER = LoggerFactory.getLogger(); + private final RouterConfig routerConfig = PluginConfigManager.getPluginConfig(RouterConfig.class); + private final InstanceStrategy> matchInstanceStrategy; private final InstanceStrategy>> mismatchInstanceStrategy; @@ -182,6 +192,9 @@ public List getMismatchInstances(String serviceName, List instances, List< private List getInstances(InstanceStrategy instanceStrategy, T tags, String serviceName, List instances, boolean isReturnAllInstancesWhenMismatch) { + if (routerConfig.isEnableMetric()) { + countRouteNum(tags, instanceStrategy); + } List resultList = new ArrayList<>(); for (I instance : instances) { if (instanceStrategy.isMatch(instance, tags, mapper)) { @@ -210,4 +223,54 @@ private InstanceStrategy getStrategy(boolean isMatch) { return isMatch ? (InstanceStrategy) matchInstanceStrategy : (InstanceStrategy) mismatchInstanceStrategy; } + + /** + * count Request + * + * @param tagsObject Tag information of routing rules + * @param strategy This is the label routing policy used to determine whether the instance matches + */ + private void countRouteNum(Object tagsObject, InstanceStrategy strategy) { + if (strategy == mismatchInstanceStrategy) { + Map tagsMap = new HashMap<>(); + initProtocolAndServiceName(tagsMap); + MetricsManager.addOrUpdateCounterMetricValue(RouterConstant.ROUTER_UNMATCHED_REQUEST_COUNT, tagsMap, 1); + return; + } + if (tagsObject instanceof Map) { + ((Map) tagsObject).forEach(this::addOrUpdateMatchedRouterCounterValue); + return; + } + if (!(tagsObject instanceof List)) { + return; + } + List> tagsList = (List>) tagsObject; + if (CollectionUtils.isEmpty(tagsList)) { + return; + } + tagsList.forEach(valueMap -> valueMap.forEach(this::addOrUpdateMatchedRouterCounterValue)); + } + + private void addOrUpdateMatchedRouterCounterValue(String key, String value) { + Map tagsMap = new HashMap<>(); + MetricsManager.getAllTagKey().forEach(tagKey -> tagsMap.put(tagKey, StringUtils.EMPTY)); + initProtocolAndServiceName(tagsMap); + String tagsName = MetricsManager.getTagKeyByRouteTagOrLaneTag(key); + if (StringUtils.isEmpty(tagsName)) { + tagsMap.put(RouterConstant.SERVICE_META_PARAMETERS, key + ":" + value); + } else { + tagsMap.put(tagsName, value); + } + MetricsManager.addOrUpdateCounterMetricValue(RouterConstant.ROUTER_DESTINATION_TAG_COUNT, tagsMap, 1); + } + + private void initProtocolAndServiceName(Map tagsMap) { + if (StringUtils.equals(source, "dubbo")) { + tagsMap.put(RouterConstant.PROTOCOL, RouterConstant.DUBBO_PROTOCOL); + tagsMap.put(RouterConstant.CLIENT_SERVICE_NAME, DubboCache.INSTANCE.getAppName()); + return; + } + tagsMap.put(RouterConstant.PROTOCOL, RouterConstant.HTTP_PROTOCOL); + tagsMap.put(RouterConstant.CLIENT_SERVICE_NAME, AppCache.INSTANCE.getAppName()); + } } diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/AbstractHandler.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/AbstractHandler.java index 99d564dc84..a0e985afc0 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/AbstractHandler.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/AbstractHandler.java @@ -16,11 +16,17 @@ package io.sermant.router.spring.handler; +import io.sermant.core.plugin.config.PluginConfigManager; +import io.sermant.router.common.cache.AppCache; +import io.sermant.router.common.config.RouterConfig; +import io.sermant.router.common.constants.RouterConstant; import io.sermant.router.common.handler.Handler; +import io.sermant.router.common.metric.MetricsManager; import io.sermant.router.common.utils.CollectionUtils; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -32,6 +38,8 @@ * @since 2023-02-21 */ public abstract class AbstractHandler implements Handler { + private final RouterConfig routerConfig = PluginConfigManager.getPluginConfig(RouterConfig.class); + /** * From the headers, obtain the request token that needs to be transparently transmitted * @@ -51,4 +59,32 @@ protected Map> getRequestTag(Map> head } return map; } + + /** + * Collect Lane Count Metric. + * + * @param laneTag lane tag + */ + protected void collectLaneCountMetric(Map> laneTag) { + if (!routerConfig.isEnableMetric()) { + return; + } + Set tagValues = new HashSet<>(); + laneTag.forEach((key, values) -> { + if (CollectionUtils.isEmpty(values)) { + return; + } + values.forEach(tagValue -> { + if (tagValues.contains(tagValue)) { + return; + } + tagValues.add(tagValue); + Map tagsMap = new HashMap<>(); + tagsMap.put(RouterConstant.LANE_TAG, key + ":" + tagValue); + tagsMap.put(RouterConstant.CLIENT_SERVICE_NAME, AppCache.INSTANCE.getAppName()); + tagsMap.put(RouterConstant.PROTOCOL, RouterConstant.HTTP_PROTOCOL); + MetricsManager.addOrUpdateCounterMetricValue(RouterConstant.LANE_TAG_COUNT, tagsMap, 1); + }); + }); + } } diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/LaneMappingHandler.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/LaneMappingHandler.java index 1a4366bb7b..d5e6da72e7 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/LaneMappingHandler.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/LaneMappingHandler.java @@ -75,6 +75,7 @@ public Map> getRequestTag(String path, String methodName, M LOGGER.fine("Lane is empty."); return tags; } + collectLaneCountMetric(laneTag); // If there is a marker in the upstream transmission that is the same as the one in this staining, // the upstream transmission shall prevail diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/LaneRequestTagHandler.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/LaneRequestTagHandler.java index 23f0176278..f18cb0a65b 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/LaneRequestTagHandler.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/LaneRequestTagHandler.java @@ -81,6 +81,7 @@ public Map> getRequestTag(String path, String methodName, M if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine("Lane is " + tags); } + collectLaneCountMetric(laneTag); return tags; } diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/ClientHttpRequestInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/ClientHttpRequestInterceptor.java index f0edb56a3e..4d0ff04652 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/ClientHttpRequestInterceptor.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/ClientHttpRequestInterceptor.java @@ -18,7 +18,11 @@ import io.sermant.core.plugin.agent.entity.ExecuteContext; import io.sermant.core.plugin.agent.interceptor.AbstractInterceptor; +import io.sermant.core.plugin.config.PluginConfigManager; import io.sermant.core.utils.LogUtils; +import io.sermant.router.common.config.RouterConfig; +import io.sermant.router.common.metric.MetricThreadLocal; +import io.sermant.router.common.metric.MetricsManager; import io.sermant.router.common.request.RequestData; import io.sermant.router.common.request.RequestTag; import io.sermant.router.common.utils.ThreadLocalUtils; @@ -37,6 +41,8 @@ * @since 2022-07-12 */ public class ClientHttpRequestInterceptor extends AbstractInterceptor { + private final RouterConfig routerConfig = PluginConfigManager.getPluginConfig(RouterConfig.class); + @Override public ExecuteContext before(ExecuteContext context) { LogUtils.printHttpRequestBeforePoint(context); @@ -48,20 +54,34 @@ public ExecuteContext before(ExecuteContext context) { String path = request.getURI().getPath(); ThreadLocalUtils.setRequestData(new RequestData(headers, path, request.getMethod().name())); } + MetricThreadLocal.setFlag(true); return context; } @Override public ExecuteContext after(ExecuteContext context) { + collectRequestCountMetric(context); ThreadLocalUtils.removeRequestData(); LogUtils.printHttpRequestAfterPoint(context); return context; } + private void collectRequestCountMetric(ExecuteContext context) { + // To prevent execution twice, after mounting and registering the plugin, this interception point is + // executed twice for a single request + Object obj = context.getObject(); + if (routerConfig.isEnableMetric() && MetricThreadLocal.getFlag() && obj instanceof HttpRequest) { + HttpRequest request = (HttpRequest) obj; + MetricsManager.collectRequestCountMetric(request.getURI()); + } + MetricThreadLocal.removeFlag(); + } + @Override public ExecuteContext onThrow(ExecuteContext context) { ThreadLocalUtils.removeRequestData(); LogUtils.printHttpRequestOnThrowPoint(context); + MetricThreadLocal.removeFlag(); return context; } diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/DiscoveryManagerInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/DiscoveryManagerInterceptor.java index 2aa3470de2..0a9e755674 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/DiscoveryManagerInterceptor.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/DiscoveryManagerInterceptor.java @@ -22,9 +22,9 @@ import io.sermant.core.plugin.config.PluginConfigManager; import io.sermant.core.plugin.service.PluginServiceManager; import io.sermant.core.utils.ReflectUtils; +import io.sermant.router.common.cache.AppCache; import io.sermant.router.common.config.RouterConfig; import io.sermant.router.common.constants.RouterConstant; -import io.sermant.router.spring.cache.AppCache; import io.sermant.router.spring.service.SpringConfigService; import io.sermant.router.spring.utils.SpringRouterUtils; diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/EurekaHttpClientInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/EurekaHttpClientInterceptor.java index 2407329935..6356078b82 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/EurekaHttpClientInterceptor.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/EurekaHttpClientInterceptor.java @@ -22,9 +22,9 @@ import io.sermant.core.plugin.agent.interceptor.AbstractInterceptor; import io.sermant.core.plugin.config.PluginConfigManager; import io.sermant.core.plugin.service.PluginServiceManager; +import io.sermant.router.common.cache.AppCache; import io.sermant.router.common.config.RouterConfig; import io.sermant.router.common.constants.RouterConstant; -import io.sermant.router.spring.cache.AppCache; import io.sermant.router.spring.service.SpringConfigService; import io.sermant.router.spring.utils.SpringRouterUtils; diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/FeignClientInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/FeignClientInterceptor.java index 179f14b56c..9ab2d0990d 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/FeignClientInterceptor.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/FeignClientInterceptor.java @@ -20,12 +20,16 @@ import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariableDefault; import feign.Request; +import io.sermant.core.common.LoggerFactory; import io.sermant.core.plugin.agent.entity.ExecuteContext; import io.sermant.core.plugin.agent.interceptor.AbstractInterceptor; import io.sermant.core.plugin.config.PluginConfigManager; import io.sermant.core.utils.LogUtils; import io.sermant.core.utils.StringUtils; +import io.sermant.router.common.config.RouterConfig; import io.sermant.router.common.config.TransmitConfig; +import io.sermant.router.common.metric.MetricThreadLocal; +import io.sermant.router.common.metric.MetricsManager; import io.sermant.router.common.request.RequestData; import io.sermant.router.common.request.RequestTag; import io.sermant.router.common.utils.CollectionUtils; @@ -33,6 +37,8 @@ import io.sermant.router.common.utils.ReflectUtils; import io.sermant.router.common.utils.ThreadLocalUtils; +import java.net.MalformedURLException; +import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -41,6 +47,8 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Optional; +import java.util.logging.Level; +import java.util.logging.Logger; /** * The client enhancement class, initiates the feign request method @@ -49,10 +57,14 @@ * @since 2022-07-12 */ public class FeignClientInterceptor extends AbstractInterceptor { + private static final Logger LOGGER = LoggerFactory.getLogger(); + private static final int EXPECT_LENGTH = 4; private final boolean canLoadHystrix; + private final RouterConfig routerConfig = PluginConfigManager.getPluginConfig(RouterConfig.class); + /** * Constructor */ @@ -70,21 +82,38 @@ public ExecuteContext before(ExecuteContext context) { setHeaders(request, headers); ThreadLocalUtils.setRequestData(new RequestData(decodeTags(headers), getPath(request.url()), request.method())); + MetricThreadLocal.setFlag(true); } return context; } @Override public ExecuteContext after(ExecuteContext context) { + collectRequestCountMetric(context); ThreadLocalUtils.removeRequestData(); LogUtils.printHttpRequestAfterPoint(context); return context; } + private void collectRequestCountMetric(ExecuteContext context) { + Object argument = context.getArguments()[0]; + if (routerConfig.isEnableMetric() && MetricThreadLocal.getFlag() && argument instanceof Request) { + Request request = (Request) argument; + try { + URL url = new URL(request.url()); + MetricsManager.collectRequestCountMetric(url); + } catch (MalformedURLException e) { + LOGGER.log(Level.SEVERE, "Failed to create URL object based on connection information", e); + } + } + MetricThreadLocal.removeFlag(); + } + @Override public ExecuteContext onThrow(ExecuteContext context) { ThreadLocalUtils.removeRequestData(); LogUtils.printHttpRequestOnThrowPoint(context); + MetricThreadLocal.removeFlag(); return context; } diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/HttpAsyncClient4xInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/HttpAsyncClient4xInterceptor.java index 2a23590146..ad138cca70 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/HttpAsyncClient4xInterceptor.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/HttpAsyncClient4xInterceptor.java @@ -24,6 +24,8 @@ import io.sermant.core.utils.StringUtils; import io.sermant.router.common.config.RouterConfig; import io.sermant.router.common.constants.RouterConstant; +import io.sermant.router.common.metric.MetricThreadLocal; +import io.sermant.router.common.metric.MetricsManager; import io.sermant.router.common.request.RequestData; import io.sermant.router.common.utils.FlowContextUtils; import io.sermant.router.common.utils.ThreadLocalUtils; @@ -31,6 +33,7 @@ import io.sermant.router.spring.utils.BaseHttpRouterUtils; import org.apache.http.Header; +import org.apache.http.HttpException; import org.apache.http.HttpHost; import org.apache.http.HttpRequest; import org.apache.http.client.methods.HttpRequestBase; @@ -38,6 +41,7 @@ import org.apache.http.nio.protocol.HttpAsyncRequestProducer; import org.apache.http.protocol.HttpContext; +import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; @@ -57,9 +61,9 @@ public class HttpAsyncClient4xInterceptor extends MarkInterceptor { private static final Logger LOGGER = LoggerFactory.getLogger(); - private static final int HTTPCONTEXT_INDEX = 2; + private static final int HTTP_CONTEXT_INDEX = 2; - private RouterConfig routerConfig = PluginConfigManager.getPluginConfig(RouterConfig.class); + private final RouterConfig routerConfig = PluginConfigManager.getPluginConfig(RouterConfig.class); /** * Pre trigger point @@ -79,10 +83,11 @@ public ExecuteContext doBefore(ExecuteContext context) throws Exception { = (HttpAsyncRequestProducer) httpAsyncRequestProducerArgument; HttpRequest httpRequest = httpAsyncRequestProducer.generateRequest(); handleXdsRouterAndUpdateHttpRequest(httpRequest, context); - Object argument = context.getArguments()[HTTPCONTEXT_INDEX]; + Object argument = context.getArguments()[HTTP_CONTEXT_INDEX]; if (!(argument instanceof HttpContext)) { return context; } + MetricThreadLocal.setFlag(true); HttpContext httpContext = (HttpContext) argument; if (StringUtils.isBlank(FlowContextUtils.getTagName())) { return context; @@ -95,7 +100,7 @@ private void parseTags(HttpContext httpContext, HttpRequest httpRequest) { Object attribute = httpContext.getAttribute(FlowContextUtils.getTagName()); if (attribute != null) { Map> map = FlowContextUtils.decodeTags(String.valueOf(attribute)); - if (map != null && map.size() > 0) { + if (map != null && !map.isEmpty()) { ThreadLocalUtils.setRequestData(new RequestData( map, httpRequest.getRequestLine().getUri(), httpRequest.getRequestLine().getMethod())); } @@ -115,13 +120,32 @@ private void parseTags(HttpContext httpContext, HttpRequest httpRequest) { @Override public ExecuteContext after(ExecuteContext context) throws Exception { LogUtils.printHttpRequestAfterPoint(context); + collectRequestCountMetric(context); return context; } + private void collectRequestCountMetric(ExecuteContext context) { + Object httpAsyncRequestProducerArgument = context.getArguments()[0]; + if (routerConfig.isEnableMetric() && MetricThreadLocal.getFlag() + && httpAsyncRequestProducerArgument instanceof HttpAsyncRequestProducer) { + HttpAsyncRequestProducer httpAsyncRequestProducer + = (HttpAsyncRequestProducer) httpAsyncRequestProducerArgument; + try { + HttpRequest httpRequest = httpAsyncRequestProducer.generateRequest(); + URI uri = URI.create(httpRequest.getRequestLine().getUri()); + MetricsManager.collectRequestCountMetric(uri); + } catch (IOException | HttpException e) { + LOGGER.log(Level.SEVERE, "Failed to generate request information", e); + } + } + MetricThreadLocal.removeFlag(); + } + @Override public ExecuteContext onThrow(ExecuteContext context) { ThreadLocalUtils.removeRequestData(); LogUtils.printHttpRequestOnThrowPoint(context); + MetricThreadLocal.removeFlag(); return context; } diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/HttpClient4xInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/HttpClient4xInterceptor.java index 9fd717d474..0ef3a38ac2 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/HttpClient4xInterceptor.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/HttpClient4xInterceptor.java @@ -24,6 +24,8 @@ import io.sermant.core.utils.StringUtils; import io.sermant.router.common.config.RouterConfig; import io.sermant.router.common.constants.RouterConstant; +import io.sermant.router.common.metric.MetricThreadLocal; +import io.sermant.router.common.metric.MetricsManager; import io.sermant.router.common.request.RequestData; import io.sermant.router.common.utils.CollectionUtils; import io.sermant.router.common.utils.FlowContextUtils; @@ -52,17 +54,16 @@ public class HttpClient4xInterceptor extends MarkInterceptor { private static final Logger LOGGER = LoggerFactory.getLogger(); - private RouterConfig routerConfig = PluginConfigManager.getPluginConfig(RouterConfig.class); + private final RouterConfig routerConfig = PluginConfigManager.getPluginConfig(RouterConfig.class); /** * Pre-trigger point * * @param context Execution context * @return Execution context - * @throws Exception Execution exception */ @Override - public ExecuteContext doBefore(ExecuteContext context) throws Exception { + public ExecuteContext doBefore(ExecuteContext context) { LogUtils.printHttpRequestBeforePoint(context); Object[] arguments = context.getArguments(); @@ -73,7 +74,7 @@ public ExecuteContext doBefore(ExecuteContext context) throws Exception { final HttpRequestBase httpRequest = (HttpRequestBase) httpRequestObject; handleXdsRouterAndUpdateHttpRequest(arguments); - + MetricThreadLocal.setFlag(true); if (StringUtils.isBlank(FlowContextUtils.getTagName())) { return context; } @@ -104,15 +105,29 @@ public ExecuteContext doBefore(ExecuteContext context) throws Exception { */ @Override public ExecuteContext after(ExecuteContext context) throws Exception { + collectRequestCountMetric(context); ThreadLocalUtils.removeRequestData(); LogUtils.printHttpRequestAfterPoint(context); return context; } + private void collectRequestCountMetric(ExecuteContext context) { + Object[] arguments = context.getArguments(); + Object httpRequestObject = arguments[1]; + if (routerConfig.isEnableMetric() && MetricThreadLocal.getFlag() + && httpRequestObject instanceof HttpRequestBase) { + final HttpRequestBase httpRequest = (HttpRequestBase) httpRequestObject; + MetricsManager.collectRequestCountMetric(httpRequest.getURI()); + context.setLocalFieldValue(RouterConstant.EXECUTE_FLAG, Boolean.TRUE); + } + MetricThreadLocal.removeFlag(); + } + @Override public ExecuteContext onThrow(ExecuteContext context) { ThreadLocalUtils.removeRequestData(); LogUtils.printHttpRequestOnThrowPoint(context); + MetricThreadLocal.removeFlag(); return context; } diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/HttpUrlConnectionConnectInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/HttpUrlConnectionConnectInterceptor.java index 6cd7decb9f..0771e0e46a 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/HttpUrlConnectionConnectInterceptor.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/HttpUrlConnectionConnectInterceptor.java @@ -26,6 +26,8 @@ import io.sermant.core.utils.StringUtils; import io.sermant.router.common.config.RouterConfig; import io.sermant.router.common.constants.RouterConstant; +import io.sermant.router.common.metric.MetricThreadLocal; +import io.sermant.router.common.metric.MetricsManager; import io.sermant.router.common.request.RequestData; import io.sermant.router.common.utils.CollectionUtils; import io.sermant.router.common.utils.FlowContextUtils; @@ -50,7 +52,7 @@ public class HttpUrlConnectionConnectInterceptor extends AbstractInterceptor { private static final Logger LOGGER = LoggerFactory.getLogger(); - private RouterConfig routerConfig = PluginConfigManager.getPluginConfig(RouterConfig.class); + private final RouterConfig routerConfig = PluginConfigManager.getPluginConfig(RouterConfig.class); @Override public ExecuteContext before(ExecuteContext context) { @@ -62,7 +64,7 @@ public ExecuteContext before(ExecuteContext context) { Map> headers = connection.getRequestProperties(); handleXdsRouterAndUpdateHttpRequest(connection); - + MetricThreadLocal.setFlag(true); String method = connection.getRequestMethod(); if (StringUtils.isBlank(FlowContextUtils.getTagName()) || CollectionUtils .isEmpty(headers.get(FlowContextUtils.getTagName()))) { @@ -89,15 +91,26 @@ private String getPath(HttpURLConnection connection) { @Override public ExecuteContext after(ExecuteContext context) { + collectRequestCountMetric(context); ThreadLocalUtils.removeRequestData(); LogUtils.printHttpRequestAfterPoint(context); return context; } + private void collectRequestCountMetric(ExecuteContext context) { + if (routerConfig.isEnableMetric() && MetricThreadLocal.getFlag()) { + HttpURLConnection connection = (HttpURLConnection) context.getObject(); + MetricsManager.collectRequestCountMetric(connection.getURL()); + context.setLocalFieldValue(RouterConstant.EXECUTE_FLAG, Boolean.TRUE); + } + MetricThreadLocal.removeFlag(); + } + @Override public ExecuteContext onThrow(ExecuteContext context) throws Exception { ThreadLocalUtils.removeRequestData(); LogUtils.printHttpRequestOnThrowPoint(context); + MetricThreadLocal.removeFlag(); return super.onThrow(context); } diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/OkHttp3ClientInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/OkHttp3ClientInterceptor.java index c85ae717e0..088c2b736e 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/OkHttp3ClientInterceptor.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/OkHttp3ClientInterceptor.java @@ -24,6 +24,8 @@ import io.sermant.core.utils.StringUtils; import io.sermant.router.common.config.RouterConfig; import io.sermant.router.common.constants.RouterConstant; +import io.sermant.router.common.metric.MetricThreadLocal; +import io.sermant.router.common.metric.MetricsManager; import io.sermant.router.common.request.RequestData; import io.sermant.router.common.utils.FlowContextUtils; import io.sermant.router.common.utils.ThreadLocalUtils; @@ -47,17 +49,16 @@ public class OkHttp3ClientInterceptor extends MarkInterceptor { private static final String FIELD_NAME = "originalRequest"; - private RouterConfig routerConfig = PluginConfigManager.getPluginConfig(RouterConfig.class); + private final RouterConfig routerConfig = PluginConfigManager.getPluginConfig(RouterConfig.class); /** * Pre-trigger point * * @param context Execution context * @return Execution context - * @throws Exception Execution exception */ @Override - public ExecuteContext doBefore(ExecuteContext context) throws Exception { + public ExecuteContext doBefore(ExecuteContext context) { LogUtils.printHttpRequestBeforePoint(context); final Optional rawRequest = getRequest(context); if (!rawRequest.isPresent()) { @@ -68,7 +69,7 @@ public ExecuteContext doBefore(ExecuteContext context) throws Exception { Headers headers = request.headers(); handleXdsRouterAndUpdateHttpRequest(context.getObject(), request); - + MetricThreadLocal.setFlag(true); if (StringUtils.isBlank(FlowContextUtils.getTagName())) { return context; } @@ -91,13 +92,27 @@ public ExecuteContext doBefore(ExecuteContext context) throws Exception { public ExecuteContext after(ExecuteContext context) throws Exception { ThreadLocalUtils.removeRequestData(); LogUtils.printHttpRequestAfterPoint(context); + collectRequestCountMetric(context); return context; } + private void collectRequestCountMetric(ExecuteContext context) { + if (routerConfig.isEnableMetric() && MetricThreadLocal.getFlag()) { + final Optional rawRequest = getRequest(context); + if (rawRequest.isPresent()) { + Request request = rawRequest.get(); + MetricsManager.collectRequestCountMetric(request.url().uri()); + context.setLocalFieldValue(RouterConstant.EXECUTE_FLAG, Boolean.TRUE); + } + } + MetricThreadLocal.removeFlag(); + } + @Override public ExecuteContext onThrow(ExecuteContext context) { ThreadLocalUtils.removeRequestData(); LogUtils.printHttpRequestOnThrowPoint(context); + MetricThreadLocal.removeFlag(); return context; } diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/OkHttpClientInterceptorChainInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/OkHttpClientInterceptorChainInterceptor.java index 1f3bb51d88..11b9771fac 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/OkHttpClientInterceptorChainInterceptor.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/OkHttpClientInterceptorChainInterceptor.java @@ -17,7 +17,6 @@ package io.sermant.router.spring.interceptor; import com.squareup.okhttp.Headers; -import com.squareup.okhttp.HttpUrl; import com.squareup.okhttp.Request; import io.sermant.core.common.LoggerFactory; @@ -27,10 +26,13 @@ import io.sermant.core.service.xds.entity.ServiceInstance; import io.sermant.router.common.config.RouterConfig; import io.sermant.router.common.constants.RouterConstant; +import io.sermant.router.common.metric.MetricThreadLocal; +import io.sermant.router.common.metric.MetricsManager; import io.sermant.router.spring.utils.BaseHttpRouterUtils; import java.io.IOException; import java.net.URI; +import java.net.URL; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -46,7 +48,7 @@ public class OkHttpClientInterceptorChainInterceptor implements Interceptor { private static final Logger LOGGER = LoggerFactory.getLogger(); - private RouterConfig routerConfig = PluginConfigManager.getPluginConfig(RouterConfig.class); + private final RouterConfig routerConfig = PluginConfigManager.getPluginConfig(RouterConfig.class); /** * Pre-trigger point @@ -58,6 +60,10 @@ public class OkHttpClientInterceptorChainInterceptor implements Interceptor { @Override public ExecuteContext before(ExecuteContext context) throws Exception { Object[] arguments = context.getArguments(); + if (!(arguments[0] instanceof Request)) { + return context; + } + MetricThreadLocal.setFlag(true); handleXdsRouterAndUpdateHttpRequest(arguments); return context; } @@ -71,11 +77,23 @@ public ExecuteContext before(ExecuteContext context) throws Exception { */ @Override public ExecuteContext after(ExecuteContext context) throws Exception { + collectRequestCountMetric(context); return context; } + private void collectRequestCountMetric(ExecuteContext context) throws IOException { + Object[] arguments = context.getArguments(); + if (routerConfig.isEnableMetric() && MetricThreadLocal.getFlag() && arguments[0] instanceof Request) { + Request request = (Request) arguments[0]; + MetricsManager.collectRequestCountMetric(request.uri()); + context.setLocalFieldValue(RouterConstant.EXECUTE_FLAG, Boolean.TRUE); + } + MetricThreadLocal.removeFlag(); + } + @Override public ExecuteContext onThrow(ExecuteContext context) { + MetricThreadLocal.removeFlag(); return context; } @@ -89,8 +107,15 @@ private Map getHeaders(Request request) { } private Request rebuildRequest(Request request, URI uri, ServiceInstance serviceInstance) { + URL url = null; + try { + url = new URL(BaseHttpRouterUtils.rebuildUrlByXdsServiceInstance(uri, serviceInstance)); + } catch (IOException e) { + LOGGER.log(Level.WARNING, "Convert url string to url failed.", e.getMessage()); + return request; + } return request.newBuilder() - .url(HttpUrl.parse(BaseHttpRouterUtils.rebuildUrlByXdsServiceInstance(uri, serviceInstance))) + .url(url) .build(); } diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/RestTemplateInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/RestTemplateInterceptor.java index 921a5aa932..f6d0966cd3 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/RestTemplateInterceptor.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/RestTemplateInterceptor.java @@ -17,8 +17,13 @@ package io.sermant.router.spring.interceptor; import io.sermant.core.plugin.agent.entity.ExecuteContext; +import io.sermant.core.plugin.config.PluginConfigManager; import io.sermant.core.utils.LogUtils; import io.sermant.core.utils.StringUtils; +import io.sermant.router.common.config.RouterConfig; +import io.sermant.router.common.constants.RouterConstant; +import io.sermant.router.common.metric.MetricThreadLocal; +import io.sermant.router.common.metric.MetricsManager; import io.sermant.router.common.request.RequestData; import io.sermant.router.common.utils.FlowContextUtils; import io.sermant.router.common.utils.ThreadLocalUtils; @@ -41,11 +46,13 @@ public class RestTemplateInterceptor extends MarkInterceptor { private static final int CALLBACK_ARG_POSITION = 2; + private final RouterConfig routerConfig = PluginConfigManager.getPluginConfig(RouterConfig.class); + @Override public ExecuteContext doBefore(ExecuteContext context) { LogUtils.printHttpRequestBeforePoint(context); Object[] arguments = context.getArguments(); - + MetricThreadLocal.setFlag(true); if (arguments != null && arguments.length > CALLBACK_ARG_LENGTH) { Object argument = arguments[CALLBACK_ARG_POSITION]; if (argument instanceof RequestCallbackWrapper) { @@ -87,13 +94,24 @@ private RequestData getRequestData(Map> tags, Object url, O public ExecuteContext after(ExecuteContext context) throws Exception { ThreadLocalUtils.removeRequestData(); LogUtils.printHttpRequestAfterPoint(context); + collectRequestCountMetric(context); return context; } + private void collectRequestCountMetric(ExecuteContext context) { + Object[] arguments = context.getArguments(); + if (routerConfig.isEnableMetric() && MetricThreadLocal.getFlag() && arguments[0] instanceof URI) { + MetricsManager.collectRequestCountMetric((URI) arguments[0]); + context.setLocalFieldValue(RouterConstant.EXECUTE_FLAG, Boolean.TRUE); + } + MetricThreadLocal.removeFlag(); + } + @Override public ExecuteContext onThrow(ExecuteContext context) throws Exception { ThreadLocalUtils.removeRequestData(); LogUtils.printHttpRequestOnThrowPoint(context); + MetricThreadLocal.removeFlag(); return context; } } diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/ServiceRegistryInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/ServiceRegistryInterceptor.java index 4f47887808..00ce7e9291 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/ServiceRegistryInterceptor.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/ServiceRegistryInterceptor.java @@ -21,10 +21,10 @@ import io.sermant.core.plugin.agent.interceptor.AbstractInterceptor; import io.sermant.core.plugin.config.PluginConfigManager; import io.sermant.core.plugin.service.PluginServiceManager; +import io.sermant.router.common.cache.AppCache; import io.sermant.router.common.config.RouterConfig; import io.sermant.router.common.constants.RouterConstant; import io.sermant.router.common.utils.ReflectUtils; -import io.sermant.router.spring.cache.AppCache; import io.sermant.router.spring.service.SpringConfigService; import io.sermant.router.spring.utils.SpringRouterUtils; diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/utils/SpringRouterUtils.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/utils/SpringRouterUtils.java index 6bdb125434..781d530223 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/utils/SpringRouterUtils.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/utils/SpringRouterUtils.java @@ -21,10 +21,10 @@ import io.sermant.core.plugin.config.PluginConfigManager; import io.sermant.core.service.xds.entity.ServiceInstance; import io.sermant.core.utils.StringUtils; +import io.sermant.router.common.cache.AppCache; import io.sermant.router.common.config.RouterConfig; import io.sermant.router.common.utils.CollectionUtils; import io.sermant.router.common.utils.ReflectUtils; -import io.sermant.router.spring.cache.AppCache; import org.springframework.cloud.client.DefaultServiceInstance; diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/BaseTransmitConfigTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/BaseTransmitConfigTest.java index 3051d0e980..0488abf359 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/BaseTransmitConfigTest.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/BaseTransmitConfigTest.java @@ -17,6 +17,7 @@ package io.sermant.router.spring; import io.sermant.core.plugin.config.PluginConfigManager; +import io.sermant.router.common.config.RouterConfig; import io.sermant.router.common.config.TransmitConfig; import org.junit.AfterClass; @@ -41,6 +42,8 @@ public static void initTransmitConfig() { mockPluginConfigManager = Mockito.mockStatic(PluginConfigManager.class); mockPluginConfigManager.when(() -> PluginConfigManager.getPluginConfig(TransmitConfig.class)) .thenReturn(new TransmitConfig()); + mockPluginConfigManager.when(() -> PluginConfigManager.getPluginConfig(RouterConfig.class)) + .thenReturn(new RouterConfig()); } /** diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/LaneMappingHandlerTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/LaneMappingHandlerTest.java index b8a3bdae36..deadbf3003 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/LaneMappingHandlerTest.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/LaneMappingHandlerTest.java @@ -16,7 +16,10 @@ package io.sermant.router.spring.handler; +import io.sermant.core.plugin.PluginManager; +import io.sermant.core.plugin.config.PluginConfigManager; import io.sermant.core.service.ServiceManager; +import io.sermant.router.common.config.RouterConfig; import io.sermant.router.spring.TestSpringConfigService; import io.sermant.router.spring.service.LaneService; import io.sermant.router.spring.service.SpringConfigService; @@ -42,6 +45,8 @@ public class LaneMappingHandlerTest { private static MockedStatic mockServiceManager; + private static MockedStatic mockPluginConfigManager; + private static TestLaneService laneService; private static TestSpringConfigService configService; @@ -60,6 +65,9 @@ public static void before() { configService = new TestSpringConfigService(); mockServiceManager.when(() -> ServiceManager.getService(SpringConfigService.class)) .thenReturn(configService); + mockPluginConfigManager = Mockito.mockStatic(PluginConfigManager.class); + mockPluginConfigManager.when(() -> PluginConfigManager.getPluginConfig(RouterConfig.class)). + thenReturn(new RouterConfig()); } /** @@ -68,6 +76,7 @@ public static void before() { @AfterClass public static void after() { mockServiceManager.close(); + mockPluginConfigManager.close(); } public LaneMappingHandlerTest() { diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/LaneRequestTagHandlerTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/LaneRequestTagHandlerTest.java index 7e8bd394a9..bc578af450 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/LaneRequestTagHandlerTest.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/LaneRequestTagHandlerTest.java @@ -16,7 +16,9 @@ package io.sermant.router.spring.handler; +import io.sermant.core.plugin.config.PluginConfigManager; import io.sermant.core.service.ServiceManager; +import io.sermant.router.common.config.RouterConfig; import io.sermant.router.spring.handler.AbstractRequestTagHandler.Keys; import io.sermant.router.spring.service.LaneService; @@ -43,6 +45,8 @@ public class LaneRequestTagHandlerTest { private static MockedStatic mockServiceManager; + private static MockedStatic mockPluginConfigManager; + private static TestLaneService laneService; private final LaneRequestTagHandler handler; @@ -56,6 +60,9 @@ public static void before() { laneService = new TestLaneService(); mockServiceManager.when(() -> ServiceManager.getService(LaneService.class)) .thenReturn(laneService); + mockPluginConfigManager = Mockito.mockStatic(PluginConfigManager.class); + mockPluginConfigManager.when(() -> PluginConfigManager.getPluginConfig(RouterConfig.class)) + .thenReturn(new RouterConfig()); } /** @@ -64,6 +71,7 @@ public static void before() { @AfterClass public static void after() { mockServiceManager.close(); + mockPluginConfigManager.close(); } public LaneRequestTagHandlerTest() { diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/DiscoveryManagerInterceptorTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/DiscoveryManagerInterceptorTest.java index 069309d3ef..6ca2ad271d 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/DiscoveryManagerInterceptorTest.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/DiscoveryManagerInterceptorTest.java @@ -22,7 +22,7 @@ import io.sermant.router.common.config.RouterConfig; import io.sermant.router.common.constants.RouterConstant; import io.sermant.router.spring.TestSpringConfigService; -import io.sermant.router.spring.cache.AppCache; +import io.sermant.router.common.cache.AppCache; import io.sermant.router.spring.service.SpringConfigService; import org.junit.AfterClass; diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/EurekaHttpClientInterceptorTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/EurekaHttpClientInterceptorTest.java index ab62b894fa..d08bfcf774 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/EurekaHttpClientInterceptorTest.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/EurekaHttpClientInterceptorTest.java @@ -24,7 +24,7 @@ import io.sermant.router.common.config.RouterConfig; import io.sermant.router.common.constants.RouterConstant; import io.sermant.router.spring.TestSpringConfigService; -import io.sermant.router.spring.cache.AppCache; +import io.sermant.router.common.cache.AppCache; import io.sermant.router.spring.service.SpringConfigService; import org.junit.AfterClass; diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/FeignClientInterceptorTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/FeignClientInterceptorTest.java index 8439bfd6d3..2365045ec3 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/FeignClientInterceptorTest.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/FeignClientInterceptorTest.java @@ -75,6 +75,8 @@ public static void before() { mockStatic.when(() -> PluginConfigManager.getPluginConfig(Mockito.any())).thenReturn(config); mockStatic.when(() -> PluginConfigManager.getPluginConfig(TransmitConfig.class)) .thenReturn(new TransmitConfig()); + mockStatic.when(() -> PluginConfigManager.getPluginConfig(RouterConfig.class)) + .thenReturn(new RouterConfig()); } @AfterClass diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/ServiceRegistryInterceptorTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/ServiceRegistryInterceptorTest.java index 5b0d145caf..d1f27f0883 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/ServiceRegistryInterceptorTest.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/ServiceRegistryInterceptorTest.java @@ -21,7 +21,7 @@ import io.sermant.router.common.config.RouterConfig; import io.sermant.router.common.constants.RouterConstant; import io.sermant.router.spring.TestSpringConfigService; -import io.sermant.router.spring.cache.AppCache; +import io.sermant.router.common.cache.AppCache; import io.sermant.router.spring.service.SpringConfigService; import org.junit.AfterClass; diff --git a/sermant-plugins/sermant-router/spring-router-service/src/main/java/io/sermant/router/spring/handler/FlowRouteHandler.java b/sermant-plugins/sermant-router/spring-router-service/src/main/java/io/sermant/router/spring/handler/FlowRouteHandler.java index 6d16440683..ddb76f1ba1 100644 --- a/sermant-plugins/sermant-router/spring-router-service/src/main/java/io/sermant/router/spring/handler/FlowRouteHandler.java +++ b/sermant-plugins/sermant-router/spring-router-service/src/main/java/io/sermant/router/spring/handler/FlowRouteHandler.java @@ -18,6 +18,7 @@ import io.sermant.core.plugin.config.PluginConfigManager; import io.sermant.core.utils.StringUtils; +import io.sermant.router.common.cache.AppCache; import io.sermant.router.common.config.RouterConfig; import io.sermant.router.common.constants.RouterConstant; import io.sermant.router.common.request.RequestData; @@ -32,7 +33,6 @@ import io.sermant.router.config.entity.ValueMatch; import io.sermant.router.config.utils.FlowRuleUtils; import io.sermant.router.config.utils.RuleUtils; -import io.sermant.router.spring.cache.AppCache; import io.sermant.router.spring.strategy.RuleStrategyHandler; import java.util.Collections; diff --git a/sermant-plugins/sermant-router/spring-router-service/src/main/java/io/sermant/router/spring/handler/TagRouteHandler.java b/sermant-plugins/sermant-router/spring-router-service/src/main/java/io/sermant/router/spring/handler/TagRouteHandler.java index 22ef7dc06e..5451c6e20c 100644 --- a/sermant-plugins/sermant-router/spring-router-service/src/main/java/io/sermant/router/spring/handler/TagRouteHandler.java +++ b/sermant-plugins/sermant-router/spring-router-service/src/main/java/io/sermant/router/spring/handler/TagRouteHandler.java @@ -16,6 +16,7 @@ package io.sermant.router.spring.handler; +import io.sermant.router.common.cache.AppCache; import io.sermant.router.common.constants.RouterConstant; import io.sermant.router.common.request.RequestData; import io.sermant.router.common.utils.CollectionUtils; @@ -28,7 +29,6 @@ import io.sermant.router.config.entity.Rule; import io.sermant.router.config.entity.ValueMatch; import io.sermant.router.config.utils.TagRuleUtils; -import io.sermant.router.spring.cache.AppCache; import io.sermant.router.spring.strategy.RuleStrategyHandler; import java.util.Collections; diff --git a/sermant-plugins/sermant-router/spring-router-service/src/main/java/io/sermant/router/spring/service/LaneServiceImpl.java b/sermant-plugins/sermant-router/spring-router-service/src/main/java/io/sermant/router/spring/service/LaneServiceImpl.java index 466ed39a2f..40ad894733 100644 --- a/sermant-plugins/sermant-router/spring-router-service/src/main/java/io/sermant/router/spring/service/LaneServiceImpl.java +++ b/sermant-plugins/sermant-router/spring-router-service/src/main/java/io/sermant/router/spring/service/LaneServiceImpl.java @@ -16,6 +16,7 @@ package io.sermant.router.spring.service; +import io.sermant.router.common.cache.AppCache; import io.sermant.router.common.constants.RouterConstant; import io.sermant.router.config.cache.ConfigCache; import io.sermant.router.config.entity.Protocol; @@ -23,7 +24,6 @@ import io.sermant.router.config.entity.RouterConfiguration; import io.sermant.router.config.entity.Rule; import io.sermant.router.config.utils.RuleUtils; -import io.sermant.router.spring.cache.AppCache; import io.sermant.router.spring.utils.RouteUtils; import java.util.Collections; diff --git a/sermant-plugins/sermant-router/spring-router-service/src/test/java/io/sermant/router/spring/RuleInitializationUtils.java b/sermant-plugins/sermant-router/spring-router-service/src/test/java/io/sermant/router/spring/RuleInitializationUtils.java index de9ed80eb0..00d07a5475 100644 --- a/sermant-plugins/sermant-router/spring-router-service/src/test/java/io/sermant/router/spring/RuleInitializationUtils.java +++ b/sermant-plugins/sermant-router/spring-router-service/src/test/java/io/sermant/router/spring/RuleInitializationUtils.java @@ -27,7 +27,7 @@ import io.sermant.router.config.entity.RouterConfiguration; import io.sermant.router.config.entity.Rule; import io.sermant.router.config.entity.ValueMatch; -import io.sermant.router.spring.cache.AppCache; +import io.sermant.router.common.cache.AppCache; import java.util.ArrayList; import java.util.Collections; diff --git a/sermant-plugins/sermant-router/spring-router-service/src/test/java/io/sermant/router/spring/handler/TagRouteHandlerTest.java b/sermant-plugins/sermant-router/spring-router-service/src/test/java/io/sermant/router/spring/handler/TagRouteHandlerTest.java index 97088bb400..311fbd64f4 100644 --- a/sermant-plugins/sermant-router/spring-router-service/src/test/java/io/sermant/router/spring/handler/TagRouteHandlerTest.java +++ b/sermant-plugins/sermant-router/spring-router-service/src/test/java/io/sermant/router/spring/handler/TagRouteHandlerTest.java @@ -23,7 +23,7 @@ import io.sermant.router.config.cache.ConfigCache; import io.sermant.router.spring.RuleInitializationUtils; import io.sermant.router.spring.TestDefaultServiceInstance; -import io.sermant.router.spring.cache.AppCache; +import io.sermant.router.common.cache.AppCache; import org.junit.AfterClass; import org.junit.Assert; diff --git a/sermant-plugins/sermant-router/spring-router-service/src/test/java/io/sermant/router/spring/service/LaneServiceTest.java b/sermant-plugins/sermant-router/spring-router-service/src/test/java/io/sermant/router/spring/service/LaneServiceTest.java index 287aa388a2..a4c1ae1115 100644 --- a/sermant-plugins/sermant-router/spring-router-service/src/test/java/io/sermant/router/spring/service/LaneServiceTest.java +++ b/sermant-plugins/sermant-router/spring-router-service/src/test/java/io/sermant/router/spring/service/LaneServiceTest.java @@ -27,7 +27,7 @@ import io.sermant.router.config.entity.RouterConfiguration; import io.sermant.router.config.entity.Rule; import io.sermant.router.config.entity.ValueMatch; -import io.sermant.router.spring.cache.AppCache; +import io.sermant.router.common.cache.AppCache; import org.junit.Assert; import org.junit.Before; diff --git a/sermant-plugins/sermant-router/spring-router-service/src/test/java/io/sermant/router/spring/service/LoadBalancerServiceTest.java b/sermant-plugins/sermant-router/spring-router-service/src/test/java/io/sermant/router/spring/service/LoadBalancerServiceTest.java index a40cae0076..c5df7c73d2 100644 --- a/sermant-plugins/sermant-router/spring-router-service/src/test/java/io/sermant/router/spring/service/LoadBalancerServiceTest.java +++ b/sermant-plugins/sermant-router/spring-router-service/src/test/java/io/sermant/router/spring/service/LoadBalancerServiceTest.java @@ -23,7 +23,7 @@ import io.sermant.router.config.cache.ConfigCache; import io.sermant.router.spring.RuleInitializationUtils; import io.sermant.router.spring.TestDefaultServiceInstance; -import io.sermant.router.spring.cache.AppCache; +import io.sermant.router.common.cache.AppCache; import org.junit.AfterClass; import org.junit.Assert;