-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Test Cases for JMX -> Prom Exporter Regexps #14155
Merged
Jackie-Jiang
merged 47 commits into
apache:master
from
suddendust:jmx_prom_metrics_exporter_tests
Oct 23, 2024
Merged
Changes from 1 commit
Commits
Show all changes
47 commits
Select commit
Hold shift + click to select a range
86c32bc
Test cases for Server Metrics
suddendust bde0d23
Merge branch 'master' of github.com:apache/pinot into jmx_prom_metric…
suddendust 51127e2
Removed hardcoded metrics
suddendust 417a8a6
WIP
suddendust f85d7c8
WIP
suddendust af4a3d2
controllerMeterTest working
suddendust 1f58846
WIP
suddendust 836db84
WIP
suddendust d938a47
WIP
suddendust 18f23e1
Finalise BrokerJMXToPromMetricsTest.java
suddendust 4436fe6
WIP
suddendust 4d2d7e1
WIP
suddendust 37462ac
Controller gauge test
suddendust ea7b328
WIP
suddendust 01d2aee
WIP
suddendust 04e7c8e
Agent working
suddendust d8f11b9
WIP
suddendust d581be8
All test cases working
suddendust 1b69b17
WIP
suddendust 10c4831
Added MinionJMXToPromMetricsTest.java
suddendust 759ec6c
Refactor
suddendust 1bbfd75
Addressed comments
suddendust 5b4e091
Rollback inadvertent changes
suddendust 4b4a94d
Added a comment
suddendust e057f79
Add comment
suddendust 4b756e0
Remove dependency
suddendust c0047a6
Address comments
suddendust 7d1e854
WIP
suddendust a300a34
WIP
suddendust 6dc98d8
WIP
suddendust 1f20b20
WIP
suddendust eff9b92
WIP
suddendust 6fdd037
WIP
suddendust 0c460ec
Addressed comments
suddendust a62a113
Rearrange code
suddendust f17c4d1
Merge branch 'master' of https://github.com/apache/pinot into jmx_pro…
suddendust 2daac0b
Separate tests for Yammer and Dropwizard metrics factory
suddendust 5489639
Addressed comments
suddendust 069962c
Added license header
suddendust 52f23c2
Added license header
suddendust ee602cc
Skip dropwizard tests in maven
suddendust f3064f5
Remove `pinotMetricsFactory` from test config
suddendust 4264af3
Remove testConfig.json
suddendust a9354eb
Remove inadvertent changes
suddendust 46899f3
Remove testConfig.json
suddendust b25b665
License
suddendust 2fcd382
Rename method from getConfigParentDir -> getConfigFile
suddendust File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
233 changes: 233 additions & 0 deletions
233
pinot-common/src/test/java/org/apache/pinot/common/metrics/PinotJMXToPromMetricsTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,233 @@ | ||
/** | ||
* Licensed to the Apache Software Foundation (ASF) under one | ||
* or more contributor license agreements. See the NOTICE file | ||
* distributed with this work for additional information | ||
* regarding copyright ownership. The ASF licenses this file | ||
* to you 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 org.apache.pinot.common.metrics; | ||
|
||
import com.google.common.base.Objects; | ||
import java.io.BufferedReader; | ||
import java.io.IOException; | ||
import java.io.StringReader; | ||
import java.net.URI; | ||
import java.net.URISyntaxException; | ||
import java.util.ArrayList; | ||
import java.util.LinkedHashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.stream.Collectors; | ||
import org.apache.pinot.common.utils.SimpleHttpResponse; | ||
import org.apache.pinot.common.utils.http.HttpClient; | ||
import org.apache.pinot.spi.config.table.TableType; | ||
import org.apache.pinot.spi.utils.builder.TableNameBuilder; | ||
import org.testng.Assert; | ||
|
||
|
||
public class PinotJMXToPromMetricsTest { | ||
|
||
protected HttpClient _httpClient; | ||
|
||
protected static final List<String> METER_TYPES = | ||
List.of("Count", "FiveMinuteRate", "MeanRate", "OneMinuteRate", "FifteenMinuteRate"); | ||
|
||
protected static final List<String> TIMER_TYPES = | ||
List.of("Count", "FiveMinuteRate", "Max", "999thPercentile", "95thPercentile", "75thPercentile", "98thPercentile", | ||
"OneMinuteRate", "50thPercentile", "99thPercentile", "FifteenMinuteRate", "Mean", "StdDev", "MeanRate", | ||
"Min"); | ||
|
||
protected static final String RAW_TABLE_NAME = "myTable"; | ||
protected static final String TABLE_NAME_WITH_TYPE = | ||
TableNameBuilder.forType(TableType.REALTIME).tableNameWithType(RAW_TABLE_NAME); | ||
|
||
protected static final String KAFKA_TOPIC = "myTopic"; | ||
protected static final String PARTITION_GROUP_ID = "partitionGroupId"; | ||
protected static final String CLIENT_ID = | ||
String.format("%s-%s-%s", TABLE_NAME_WITH_TYPE, KAFKA_TOPIC, PARTITION_GROUP_ID); | ||
protected static final String TABLE_STREAM_NAME = String.format("%s_%s", TABLE_NAME_WITH_TYPE, KAFKA_TOPIC); | ||
|
||
protected static final List<String> EXPORTED_LABELS_FOR_TABLE_NAME_TABLE_TYPE = | ||
List.of("table", "myTable", "tableType", "REALTIME"); | ||
|
||
protected static final List<String> EXPORTED_LABELS_FOR_CLIENT_ID = | ||
List.of("partition", PARTITION_GROUP_ID, "table", RAW_TABLE_NAME, "tableType", TableType.REALTIME.toString(), | ||
"topic", KAFKA_TOPIC); | ||
|
||
protected void assertGaugeExportedCorrectly(String exportedGaugePrefix, String exportedMetricPrefix) | ||
throws IOException, URISyntaxException { | ||
List<ServerJMXToPromMetricsTest.PromMetric> promMetrics = | ||
parseExportedPromMetrics(getExportedPromMetrics().getResponse()); | ||
Assert.assertTrue(promMetrics.contains( | ||
ServerJMXToPromMetricsTest.PromMetric.withName(exportedMetricPrefix + exportedGaugePrefix + "_" + "Value"))); | ||
} | ||
|
||
protected void assertGaugeExportedCorrectly(String exportedGaugePrefix, List<String> labels, | ||
String exportedMetricPrefix) | ||
throws IOException, URISyntaxException { | ||
List<ServerJMXToPromMetricsTest.PromMetric> promMetrics = | ||
parseExportedPromMetrics(getExportedPromMetrics().getResponse()); | ||
Assert.assertTrue(promMetrics.contains(ServerJMXToPromMetricsTest.PromMetric.withNameAndLabels( | ||
exportedMetricPrefix + exportedGaugePrefix + "_" + "Value", labels))); | ||
} | ||
|
||
protected void assertTimerExportedCorrectly(String exportedTimerPrefix, String exportedMetricPrefix) | ||
throws IOException, URISyntaxException { | ||
List<ServerJMXToPromMetricsTest.PromMetric> promMetrics = | ||
parseExportedPromMetrics(getExportedPromMetrics().getResponse()); | ||
for (String meterType : TIMER_TYPES) { | ||
Assert.assertTrue(promMetrics.contains(ServerJMXToPromMetricsTest.PromMetric.withName( | ||
exportedMetricPrefix + exportedTimerPrefix + "_" + meterType))); | ||
} | ||
} | ||
|
||
protected void assertTimerExportedCorrectly(String exportedTimerPrefix, List<String> labels, | ||
String exportedMetricPrefix) | ||
throws IOException, URISyntaxException { | ||
List<ServerJMXToPromMetricsTest.PromMetric> promMetrics = | ||
parseExportedPromMetrics(getExportedPromMetrics().getResponse()); | ||
for (String meterType : METER_TYPES) { | ||
Assert.assertTrue(promMetrics.contains(ServerJMXToPromMetricsTest.PromMetric.withNameAndLabels( | ||
exportedMetricPrefix + exportedTimerPrefix + "_" + meterType, labels))); | ||
} | ||
} | ||
|
||
protected void assertMeterExportedCorrectly(String exportedMeterPrefix, String exportedMetricPrefix) | ||
throws IOException, URISyntaxException { | ||
List<ServerJMXToPromMetricsTest.PromMetric> promMetrics = | ||
parseExportedPromMetrics(getExportedPromMetrics().getResponse()); | ||
for (String meterType : METER_TYPES) { | ||
Assert.assertTrue(promMetrics.contains(ServerJMXToPromMetricsTest.PromMetric.withName( | ||
exportedMetricPrefix + exportedMeterPrefix + "_" + meterType))); | ||
} | ||
} | ||
|
||
protected void assertMeterExportedCorrectly(String exportedMeterPrefix, List<String> labels, | ||
String exportedMetricPrefix) | ||
throws IOException, URISyntaxException { | ||
List<ServerJMXToPromMetricsTest.PromMetric> promMetrics = | ||
parseExportedPromMetrics(getExportedPromMetrics().getResponse()); | ||
for (String meterType : METER_TYPES) { | ||
Assert.assertTrue(promMetrics.contains(ServerJMXToPromMetricsTest.PromMetric.withNameAndLabels( | ||
exportedMetricPrefix + exportedMeterPrefix + "_" + meterType, labels))); | ||
} | ||
} | ||
|
||
protected List<ServerJMXToPromMetricsTest.PromMetric> parseExportedPromMetrics(String response) | ||
throws IOException { | ||
|
||
List<ServerJMXToPromMetricsTest.PromMetric> exportedPromMetrics = new ArrayList<>(); | ||
|
||
BufferedReader reader = new BufferedReader(new StringReader(response)); | ||
gortiz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
String line; | ||
while ((line = reader.readLine()) != null) { | ||
if (line.startsWith("pinot_")) { | ||
exportedPromMetrics.add(ServerJMXToPromMetricsTest.PromMetric.fromExportedMetric(line)); | ||
} | ||
} | ||
reader.close(); | ||
return exportedPromMetrics; | ||
} | ||
|
||
protected SimpleHttpResponse getExportedPromMetrics() | ||
throws IOException, URISyntaxException { | ||
return _httpClient.sendGetRequest(new URI("http://localhost:9021/metrics")); | ||
} | ||
|
||
public static class PromMetric { | ||
gortiz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
private final String _metricName; | ||
private final Map<String, String> _labels; | ||
|
||
public String getMetricName() { | ||
return _metricName; | ||
} | ||
|
||
public Map<String, String> getLabels() { | ||
return _labels; | ||
} | ||
|
||
private PromMetric(String metricName, Map<String, String> labels) { | ||
_metricName = metricName; | ||
_labels = labels; | ||
} | ||
|
||
public static PromMetric fromExportedMetric(String exportedMetric) { | ||
int spaceIndex = exportedMetric.indexOf(' '); | ||
String metricWithoutVal = exportedMetric.substring(0, spaceIndex); | ||
int braceIndex = metricWithoutVal.indexOf('{'); | ||
|
||
if (braceIndex != -1) { | ||
String metricName = metricWithoutVal.substring(0, braceIndex); | ||
String labelsString = metricWithoutVal.substring(braceIndex + 1, metricWithoutVal.lastIndexOf('}')); | ||
Map<String, String> labels = parseLabels(labelsString); | ||
return new PromMetric(metricName, labels); | ||
} else { | ||
return new PromMetric(metricWithoutVal, new LinkedHashMap<>()); | ||
} | ||
} | ||
|
||
private static Map<String, String> parseLabels(String labelsString) { | ||
return labelsString.isEmpty() ? new LinkedHashMap<>() | ||
: java.util.Arrays.stream(labelsString.split(",")).map(kvPair -> kvPair.split("=")) | ||
.collect(Collectors.toMap(kv -> kv[0], kv -> removeQuotes(kv[1]), (v1, v2) -> v2, LinkedHashMap::new)); | ||
} | ||
|
||
private static String removeQuotes(String value) { | ||
return value.startsWith("\"") ? value.substring(1, value.length() - 1) : value; | ||
} | ||
|
||
public static PromMetric withName(String metricName) { | ||
return new PromMetric(metricName, new LinkedHashMap<>()); | ||
} | ||
|
||
public static PromMetric withNameAndLabels(String metricName, List<String> labels) { | ||
Map<String, String> labelMap = new LinkedHashMap<>(); | ||
for (int i = 0; i < labels.size(); i += 2) { | ||
labelMap.put(labels.get(i), labels.get(i + 1)); | ||
} | ||
return new PromMetric(metricName, labelMap); | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) { | ||
return true; | ||
} | ||
if (o == null || getClass() != o.getClass()) { | ||
return false; | ||
} | ||
PromMetric that = (PromMetric) o; | ||
return Objects.equal(_metricName, that._metricName) && Objects.equal(_labels, that._labels); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hashCode(_metricName, _labels); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
StringBuilder sb = new StringBuilder(_metricName); | ||
if (!_labels.isEmpty()) { | ||
sb.append('{'); | ||
sb.append(_labels.entrySet().stream().map(e -> e.getKey() + "=\"" + e.getValue() + "\"") | ||
.collect(Collectors.joining(","))); | ||
sb.append('}'); | ||
} | ||
return sb.toString(); | ||
} | ||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we changing the config as part of the test PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I'll rollback this. It's just that certain metrics aren't getting exported right now -> So I'll have to create filters for these metrics in code now which I wanted to avoid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is caught by the tests, that is a good sign that the tests are working as expected. I think it is okay to have them in the same PR. Let's add the missing ones in the PR description
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added it in the description