Fix the bug that error occurs in JMX metrics exporter when resource name contains '*' (#2992)

This commit is contained in:
quguai 2022-12-08 17:58:24 +08:00 committed by LearningGp
parent 9f3712eed7
commit 59a32994cd
2 changed files with 82 additions and 3 deletions

View File

@ -20,12 +20,13 @@ package com.alibaba.csp.sentinel.metric.exporter.jmx;
import com.alibaba.csp.sentinel.config.SentinelConfig; import com.alibaba.csp.sentinel.config.SentinelConfig;
import com.alibaba.csp.sentinel.log.RecordLog; import com.alibaba.csp.sentinel.log.RecordLog;
import com.alibaba.csp.sentinel.node.metric.MetricNode; import com.alibaba.csp.sentinel.node.metric.MetricNode;
import com.alibaba.csp.sentinel.util.StringUtil;
import java.util.HashSet; import javax.management.ObjectName;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.regex.Pattern;
/** /**
* the metric bean writer, it provides {@link MetricBeanWriter#write} method for register the * the metric bean writer, it provides {@link MetricBeanWriter#write} method for register the
@ -41,6 +42,8 @@ public class MetricBeanWriter {
private static final String DEFAULT_APP_NAME = "sentinel-application"; private static final String DEFAULT_APP_NAME = "sentinel-application";
private static final Pattern SPECIAL_CHARACTER_PATTERN = Pattern.compile("[*?=:\"\n]");
/** /**
* write the MetricNode value to MetricBean * write the MetricNode value to MetricBean
* if the MetricBean is not registered into {@link MBeanRegistry}, * if the MetricBean is not registered into {@link MBeanRegistry},
@ -68,7 +71,10 @@ public class MetricBeanWriter {
long version = System.currentTimeMillis(); long version = System.currentTimeMillis();
// set or update the new metric value // set or update the new metric value
for (MetricNode metricNode : map.values()) { for (MetricNode metricNode : map.values()) {
final String mBeanName = "Sentinel:type=Metric,resource=" + metricNode.getResource() // Fix JMX Metrics export error: https://github.com/alibaba/Sentinel/issues/2989
// Without escape, it will throw "cannot add mbean for pattern name" or "invalid character in value part of property" exception
String resourceName = escapeSpecialCharacter(metricNode.getResource());
final String mBeanName = "Sentinel:type=Metric,resource=" + resourceName
+",classification=" + metricNode.getClassification() +",classification=" + metricNode.getClassification()
+",appName=" + appName; +",appName=" + appName;
MetricBean metricBean = mBeanRegistry.findMBean(mBeanName); MetricBean metricBean = mBeanRegistry.findMBean(mBeanName);
@ -95,4 +101,17 @@ public class MetricBeanWriter {
} }
} }
} }
/**
* escape only when arg has special character eg.(*,?,\n,\")
*
* @param resourceName need escape resource name
* @return escaped characters
*/
public static String escapeSpecialCharacter(String resourceName) {
if (StringUtil.isBlank(resourceName) || !SPECIAL_CHARACTER_PATTERN.matcher(resourceName).find()) {
return resourceName;
}
return ObjectName.quote(resourceName);
}
} }

View File

@ -0,0 +1,60 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.alibaba.cps.sentinel.metric.exporter;
import com.alibaba.csp.sentinel.metric.exporter.jmx.MetricBeanWriter;
import org.junit.Assert;
import org.junit.Test;
/**
* {@link com.alibaba.csp.sentinel.metric.exporter.jmx.MetricBeanWriter} unit test
*
* @author quguai
* @date 2022/12/7 21:33
*/
public class MetricBeanWriterTest {
@Test
public void testEscapeSpecialCharacter() {
String character = MetricBeanWriter.escapeSpecialCharacter(null);
Assert.assertNull(character);
character = MetricBeanWriter.escapeSpecialCharacter("");
Assert.assertEquals("", character);
character = MetricBeanWriter.escapeSpecialCharacter("sentinel");
Assert.assertEquals("sentinel", character);
character = MetricBeanWriter.escapeSpecialCharacter("*sentinel");
Assert.assertEquals("\"\\*sentinel\"", character);
character = MetricBeanWriter.escapeSpecialCharacter("?sentinel");
Assert.assertEquals("\"\\?sentinel\"", character);
character = MetricBeanWriter.escapeSpecialCharacter("\nsentinel");
Assert.assertEquals("\"\\nsentinel\"", character);
character = MetricBeanWriter.escapeSpecialCharacter("\"sentinel");
Assert.assertEquals("\"\\\"sentinel\"", character);
character = MetricBeanWriter.escapeSpecialCharacter("=sentinel");
Assert.assertEquals("\"=sentinel\"", character);
character = MetricBeanWriter.escapeSpecialCharacter(":sentinel");
Assert.assertEquals("\":sentinel\"", character);
}
}