diff --git a/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/utils/ClassUtils.java b/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/utils/ClassUtils.java index f085709c1..c6c7b4874 100644 --- a/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/utils/ClassUtils.java +++ b/polaris-common/polaris-model/src/main/java/com/tencent/polaris/api/utils/ClassUtils.java @@ -27,7 +27,7 @@ */ public class ClassUtils { - private static final Logger LOG = LoggerFactory.getLogger(RuleUtils.class); + private static final Logger LOG = LoggerFactory.getLogger(ClassUtils.class); /** * Check if class is present. diff --git a/polaris-plugins/polaris-plugins-observability/stat-prometheus/src/main/java/com/tencent/polaris/plugins/stat/prometheus/handler/CommonHandler.java b/polaris-plugins/polaris-plugins-observability/stat-prometheus/src/main/java/com/tencent/polaris/plugins/stat/prometheus/handler/CommonHandler.java index 8cac60e59..e059bfcc4 100644 --- a/polaris-plugins/polaris-plugins-observability/stat-prometheus/src/main/java/com/tencent/polaris/plugins/stat/prometheus/handler/CommonHandler.java +++ b/polaris-plugins/polaris-plugins-observability/stat-prometheus/src/main/java/com/tencent/polaris/plugins/stat/prometheus/handler/CommonHandler.java @@ -20,6 +20,8 @@ import com.tencent.polaris.api.plugin.stat.CircuitBreakGauge; import com.tencent.polaris.api.plugin.stat.RateLimitGauge; import com.tencent.polaris.api.pojo.InstanceGauge; +import com.tencent.polaris.api.utils.CollectionUtils; +import com.tencent.polaris.api.utils.StringUtils; import com.tencent.polaris.plugins.stat.common.model.AbstractSignatureStatInfoCollector; import com.tencent.polaris.plugins.stat.common.model.StatMetric; import com.tencent.polaris.plugins.stat.common.model.StatRevisionMetric; @@ -28,10 +30,8 @@ import com.tencent.polaris.plugins.stat.common.model.SystemMetricModel.SystemMetricName; import io.prometheus.client.Gauge; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; +import java.util.*; +import java.util.regex.Pattern; import static com.tencent.polaris.plugins.stat.common.model.SystemMetricModel.SystemMetricValue.NULL_VALUE; @@ -87,7 +87,18 @@ public static String[] getOrderedMetricLabelValues(Map labels, S return orderValue; } - public static Map convertInsGaugeToLabels(InstanceGauge insGauge, String sdkIP) { + static String convertMethod(String originalMethod, List pathRegexPatternList) { + if (StringUtils.isNotBlank(originalMethod) && CollectionUtils.isNotEmpty(pathRegexPatternList)) { + for (Pattern pattern : pathRegexPatternList) { + if (pattern.matcher(originalMethod).matches()) { + return pattern.pattern(); + } + } + } + return originalMethod; + } + + public static Map convertInsGaugeToLabels(InstanceGauge insGauge, String sdkIP, List pathRegexPatternList) { Map labels = new HashMap<>(); for (String labelName : SystemMetricLabelOrder.INSTANCE_GAUGE_LABEL_ORDER) { switch (labelName) { @@ -98,7 +109,8 @@ public static Map convertInsGaugeToLabels(InstanceGauge insGauge addLabel(labelName, insGauge.getService(), labels); break; case SystemMetricName.CALLEE_METHOD: - addLabel(labelName, insGauge.getMethod(), labels); + String method = convertMethod(insGauge.getMethod(), pathRegexPatternList); + addLabel(labelName, method, labels); break; case SystemMetricModel.SystemMetricName.CALLEE_INSTANCE: addLabel(labelName, buildAddress(insGauge.getHost(), insGauge.getPort()), labels); @@ -137,7 +149,7 @@ public static Map convertInsGaugeToLabels(InstanceGauge insGauge return labels; } - public static Map convertCircuitBreakToLabels(CircuitBreakGauge gauge, String callerIp) { + public static Map convertCircuitBreakToLabels(CircuitBreakGauge gauge, String callerIp, List pathRegexPatternList) { Map labels = new HashMap<>(); for (String labelName : SystemMetricModel.SystemMetricLabelOrder.CIRCUIT_BREAKER_LABEL_ORDER) { switch (labelName) { @@ -148,7 +160,8 @@ public static Map convertCircuitBreakToLabels(CircuitBreakGauge addLabel(labelName, gauge.getService(), labels); break; case SystemMetricName.CALLEE_METHOD: - addLabel(labelName, gauge.getMethod(), labels); + String method = convertMethod(gauge.getMethod(), pathRegexPatternList); + addLabel(labelName, method, labels); break; case SystemMetricName.CALLEE_SUBSET: addLabel(labelName, gauge.getSubset(), labels); @@ -182,7 +195,7 @@ public static Map convertCircuitBreakToLabels(CircuitBreakGauge return labels; } - public static Map convertRateLimitGaugeToLabels(RateLimitGauge rateLimitGauge) { + public static Map convertRateLimitGaugeToLabels(RateLimitGauge rateLimitGauge, List pathRegexPatternList) { Map labels = new HashMap<>(); for (String labelName : SystemMetricModel.SystemMetricLabelOrder.RATELIMIT_GAUGE_LABEL_ORDER) { switch (labelName) { @@ -193,7 +206,8 @@ public static Map convertRateLimitGaugeToLabels(RateLimitGauge r addLabel(labelName, rateLimitGauge.getService(), labels); break; case SystemMetricName.CALLEE_METHOD: - addLabel(labelName, rateLimitGauge.getMethod(), labels); + String method = convertMethod(rateLimitGauge.getMethod(), pathRegexPatternList); + addLabel(labelName, method, labels); break; case SystemMetricName.CALLER_LABELS: addLabel(labelName, rateLimitGauge.getLabels(), labels); diff --git a/polaris-plugins/polaris-plugins-observability/stat-prometheus/src/main/java/com/tencent/polaris/plugins/stat/prometheus/handler/PrometheusHandlerConfig.java b/polaris-plugins/polaris-plugins-observability/stat-prometheus/src/main/java/com/tencent/polaris/plugins/stat/prometheus/handler/PrometheusHandlerConfig.java index e724755be..feba39d9a 100644 --- a/polaris-plugins/polaris-plugins-observability/stat-prometheus/src/main/java/com/tencent/polaris/plugins/stat/prometheus/handler/PrometheusHandlerConfig.java +++ b/polaris-plugins/polaris-plugins-observability/stat-prometheus/src/main/java/com/tencent/polaris/plugins/stat/prometheus/handler/PrometheusHandlerConfig.java @@ -23,6 +23,9 @@ import com.tencent.polaris.api.utils.StringUtils; import com.tencent.polaris.factory.util.TimeStrJsonDeserializer; +import java.util.ArrayList; +import java.util.List; + /** * @author wallezhang */ @@ -50,6 +53,9 @@ public class PrometheusHandlerConfig implements Verifier { @JsonProperty private Boolean openGzip = false; + @JsonProperty + private List pathRegexList = new ArrayList<>(); + public PrometheusHandlerConfig() { } @@ -158,6 +164,14 @@ public void setService(String service) { this.service = service; } + public List getPathRegexList() { + return pathRegexList; + } + + public void setPathRegexList(List pathRegexList) { + this.pathRegexList = pathRegexList; + } + @Override public String toString() { return "PrometheusHandlerConfig{" + @@ -168,6 +182,7 @@ public String toString() { ", service='" + service + '\'' + ", pushInterval=" + pushInterval + ", openGzip=" + openGzip + + ", pathRegexList=" + pathRegexList + '}'; } } diff --git a/polaris-plugins/polaris-plugins-observability/stat-prometheus/src/main/java/com/tencent/polaris/plugins/stat/prometheus/plugin/PrometheusReporter.java b/polaris-plugins/polaris-plugins-observability/stat-prometheus/src/main/java/com/tencent/polaris/plugins/stat/prometheus/plugin/PrometheusReporter.java index cce788bfb..7489b0820 100644 --- a/polaris-plugins/polaris-plugins-observability/stat-prometheus/src/main/java/com/tencent/polaris/plugins/stat/prometheus/plugin/PrometheusReporter.java +++ b/polaris-plugins/polaris-plugins-observability/stat-prometheus/src/main/java/com/tencent/polaris/plugins/stat/prometheus/plugin/PrometheusReporter.java @@ -31,6 +31,7 @@ import com.tencent.polaris.api.plugin.stat.*; import com.tencent.polaris.api.pojo.InstanceGauge; import com.tencent.polaris.api.pojo.ServiceKey; +import com.tencent.polaris.api.utils.CollectionUtils; import com.tencent.polaris.api.utils.IPAddressUtils; import com.tencent.polaris.api.utils.StringUtils; import com.tencent.polaris.client.pojo.Node; @@ -48,15 +49,13 @@ import org.slf4j.Logger; import java.io.IOException; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.regex.Pattern; /** * PrometheusReporter plugin @@ -101,6 +100,8 @@ public class PrometheusReporter implements StatReporter, PluginConfigProvider, H private final Map pushGatewayMap = new ConcurrentHashMap<>(); + private final List pathRegexPatternList = new ArrayList<>(); + public PrometheusReporter() { this.container = new StatInfoCollectorContainer(); this.sampleMapping = new HashMap<>(); @@ -131,6 +132,12 @@ public void postContextInit(Extensions extensions) throws PolarisException { this.serviceAddressRepository = new ServiceAddressRepository(Collections.singletonList(this.config.getAddress()), extensions.getValueContext().getClientId(), extensions, new ServiceKey(config.getNamespace(), config.getService())); + if (CollectionUtils.isNotEmpty(config.getPathRegexList())) { + for (String pathRegex : config.getPathRegexList()) { + pathRegexPatternList.add(Pattern.compile(pathRegex)); + } + } + this.initHandle(); } @@ -173,7 +180,7 @@ public void handle(StatInfo statInfo) { public void handleRouterGauge(InstanceGauge instanceGauge) { if (null != container && null != container.getInsCollector()) { container.getInsCollector().collectStatInfo(instanceGauge, - CommonHandler.convertInsGaugeToLabels(instanceGauge, sdkIP), + CommonHandler.convertInsGaugeToLabels(instanceGauge, sdkIP, pathRegexPatternList), MetricValueAggregationStrategyCollections.SERVICE_CALL_STRATEGY); } } @@ -181,7 +188,7 @@ public void handleRouterGauge(InstanceGauge instanceGauge) { public void handleCircuitBreakGauge(CircuitBreakGauge circuitBreakGauge) { if (null != container && null != container.getCircuitBreakerCollector()) { container.getCircuitBreakerCollector().collectStatInfo(circuitBreakGauge, - CommonHandler.convertCircuitBreakToLabels(circuitBreakGauge, sdkIP), + CommonHandler.convertCircuitBreakToLabels(circuitBreakGauge, sdkIP, pathRegexPatternList), MetricValueAggregationStrategyCollections.CIRCUIT_BREAK_STRATEGY); } } @@ -189,7 +196,7 @@ public void handleCircuitBreakGauge(CircuitBreakGauge circuitBreakGauge) { public void handleRateLimitGauge(RateLimitGauge rateLimitGauge) { if (null != container && null != container.getRateLimitCollector()) { container.getRateLimitCollector().collectStatInfo(rateLimitGauge, - CommonHandler.convertRateLimitGaugeToLabels(rateLimitGauge), + CommonHandler.convertRateLimitGaugeToLabels(rateLimitGauge, pathRegexPatternList), MetricValueAggregationStrategyCollections.RATE_LIMIT_STRATEGY); } } diff --git a/polaris-plugins/polaris-plugins-observability/stat-prometheus/src/test/java/com/tencent/polaris/plugins/stat/prometheus/handler/CommonHandlerTest.java b/polaris-plugins/polaris-plugins-observability/stat-prometheus/src/test/java/com/tencent/polaris/plugins/stat/prometheus/handler/CommonHandlerTest.java new file mode 100644 index 000000000..66216c233 --- /dev/null +++ b/polaris-plugins/polaris-plugins-observability/stat-prometheus/src/test/java/com/tencent/polaris/plugins/stat/prometheus/handler/CommonHandlerTest.java @@ -0,0 +1,158 @@ +/* + * Tencent is pleased to support the open source community by making polaris-java available. + * + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.polaris.plugins.stat.prometheus.handler; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.regex.Pattern; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test for {@link CommonHandler}. + * + * @author Haotian Zhang + */ +public class CommonHandlerTest { + + @Test + public void testConvertMethod_WhenMethodMatchesFirstPattern() { + // 准备 + String originalMethod = "/api/v1/users"; + List patterns = Arrays.asList( + Pattern.compile("/api/v1/.*"), + Pattern.compile("/api/v2/.*") + ); + + // 执行 + String result = CommonHandler.convertMethod(originalMethod, patterns); + + // 验证 + assertThat(result).isEqualTo("/api/v1/.*"); + } + + @Test + public void testConvertMethod_WhenMethodMatchesSecondPattern() { + // 准备 + String originalMethod = "/api/v2/orders"; + List patterns = Arrays.asList( + Pattern.compile("/api/v1/.*"), + Pattern.compile("/api/v2/.*") + ); + + // 执行 + String result = CommonHandler.convertMethod(originalMethod, patterns); + + // 验证 + assertThat(result).isEqualTo("/api/v2/.*"); + } + + @Test + public void testConvertMethod_WhenMethodDoesNotMatchAnyPattern() { + // 准备 + String originalMethod = "/api/v3/products"; + List patterns = Arrays.asList( + Pattern.compile("/api/v1/.*"), + Pattern.compile("/api/v2/.*") + ); + + // 执行 + String result = CommonHandler.convertMethod(originalMethod, patterns); + + // 验证 + assertThat(result).isEqualTo("/api/v3/products"); + } + + @Test + public void testConvertMethod_WithEmptyPatternList() { + // 准备 + String originalMethod = "/api/v1/users"; + List patterns = Collections.emptyList(); + + // 执行 + String result = CommonHandler.convertMethod(originalMethod, patterns); + + // 验证 + assertThat(result).isEqualTo("/api/v1/users"); + } + + @Test + public void testConvertMethod_WithNullPatternList() { + // 准备 + String originalMethod = "/api/v1/users"; + List patterns = null; + + // 执行 + String result = CommonHandler.convertMethod(originalMethod, patterns); + + // 验证 + assertThat(result).isEqualTo("/api/v1/users"); + } + + @Test + public void testConvertMethod_WithNullOriginalMethod() { + // 准备 + String originalMethod = null; + List patterns = Arrays.asList( + Pattern.compile("/api/v1/.*"), + Pattern.compile("/api/v2/.*") + ); + + // 执行 + String result = CommonHandler.convertMethod(originalMethod, patterns); + + // 验证 + assertThat(result).isNull(); + } + + @Test + public void testConvertMethod_WithComplexPatterns() { + // 准备 + String originalMethod = "/user/12345/profile"; + List patterns = Arrays.asList( + Pattern.compile("/user/\\d+/profile"), + Pattern.compile("/product/\\d+/detail") + ); + + // 执行 + String result = CommonHandler.convertMethod(originalMethod, patterns); + + // 验证 + assertThat(result).isEqualTo("/user/\\d+/profile"); + } + + @Test + public void testConvertMethod_WithExactMatchPattern() { + // 准备 + String originalMethod = "GET"; + List patterns = Arrays.asList( + Pattern.compile("GET"), + Pattern.compile("POST"), + Pattern.compile("PUT") + ); + + // 执行 + String result = CommonHandler.convertMethod(originalMethod, patterns); + + // 验证 + assertThat(result).isEqualTo("GET"); + } +} diff --git a/polaris-plugins/polaris-plugins-observability/stat-prometheus/src/test/java/com/tencent/polaris/plugins/stat/prometheus/plugin/PrometheusReporterTest.java b/polaris-plugins/polaris-plugins-observability/stat-prometheus/src/test/java/com/tencent/polaris/plugins/stat/prometheus/plugin/PrometheusReporterTest.java index a89379238..251c58c0c 100644 --- a/polaris-plugins/polaris-plugins-observability/stat-prometheus/src/test/java/com/tencent/polaris/plugins/stat/prometheus/plugin/PrometheusReporterTest.java +++ b/polaris-plugins/polaris-plugins-observability/stat-prometheus/src/test/java/com/tencent/polaris/plugins/stat/prometheus/plugin/PrometheusReporterTest.java @@ -374,14 +374,14 @@ private Double getCircuitBreakerResult(DefaultCircuitBreakResult example, private Map getServiceCallLabels(MetricValueAggregationStrategy strategy, InstanceGauge gauge) { - Map labels = CommonHandler.convertInsGaugeToLabels(gauge, handler.getSdkIP()); + Map labels = CommonHandler.convertInsGaugeToLabels(gauge, handler.getSdkIP(), null); labels.put(SystemMetricModel.SystemMetricName.METRIC_NAME_LABEL, strategy.getStrategyName()); return labels; } private Map getCircuitBreakerLabels(MetricValueAggregationStrategy strategy, CircuitBreakGauge gauge) { - Map labels = CommonHandler.convertCircuitBreakToLabels(gauge, handler.getSdkIP()); + Map labels = CommonHandler.convertCircuitBreakToLabels(gauge, handler.getSdkIP(), null); labels.put(SystemMetricModel.SystemMetricName.METRIC_NAME_LABEL, strategy.getStrategyName()); return labels; }