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.log.RecordLog;
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.Map;
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
@ -41,6 +42,8 @@ public class MetricBeanWriter {
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
* if the MetricBean is not registered into {@link MBeanRegistry},
@ -68,7 +71,10 @@ public class MetricBeanWriter {
long version = System.currentTimeMillis();
// set or update the new metric value
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()
+",appName=" + appName;
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);
}
}