Skip to content

Commit

Permalink
Fix parsing _count metrics and keep just custom labels in the labels …
Browse files Browse the repository at this point in the history
…variable (#181)

## Description

This PR fixes two issues that I encountered during testing the new
metrics collector:

1) in case that we have metric with `_count` suffix and there is no
histogram or summary, the metric is simply skipped. This is resolved by
adding check for `TYPE` line where the type of the metric is parsed and
in case that we go with the `_count` branch, which doesn't fit to the
histogram or summary, it will pick type based on this variable
2) in case that the name is same, but the labels are different, we are
putting everything into the first metric (so the labels difference is
really ignored). This is now fixed by comparing the "custom labels" in
the current histogram/summary and the newly parsed (again custom) labels
from the new metric.

## Type of Change

* Bug fix

## Checklist

- [X] My code follows the style guidelines of this project
- [X] I have performed a self-review of my own code
- [X] I have commented my code, particularly in hard-to-understand areas
- [X] I have made corresponding changes to the documentation
- [X] My changes generate no new warnings
- [X] I have added tests that prove my fix is effective or that my
feature works
- [X] New and existing unit/integration tests pass locally with my
changes
  • Loading branch information
im-konge authored Sep 3, 2024
1 parent 4e4e64a commit 7510759
Showing 1 changed file with 49 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,47 +32,69 @@ public static List<Metric> parse(String data) throws IOException {
List<Metric> metrics = new ArrayList<>();
BufferedReader reader = new BufferedReader(new StringReader(data));
String line;
String type = "";
Histogram currentHistogram = null;
Summary currentSummary = null;

while ((line = reader.readLine()) != null) {
String[] parts = line.split(" ");

if (line.startsWith("#")) {
continue; // Skip comments and type/help definitions
if (line.contains("TYPE")) {
type = parts[3];
}
continue; // Skip comments and help definition
}
String[] parts = line.split(" ");

if (parts.length == 2) {
String metricNameAndLabels = parts[0];
double value = Double.parseDouble(parts[1]);

String[] nameAndLabels = parseNameAndLabels(metricNameAndLabels);
String name = nameAndLabels[0];
Map<String, String> labels = parseLabels(nameAndLabels[1]);
// `customLabels` represents labels that are not part of the Prometheus metrics
// (like buckets or summary) - the `le` and `quantile` labels are removed,
// because they are parsed in a different way
Map<String, String> customLabels = getCustomLabels(labels);

if (name.endsWith("_total")) {
metrics.add(new Counter(name, labels, line, value));
metrics.add(new Counter(name, customLabels, line, value));
} else if (name.contains("_bucket")) {
if (currentHistogram == null || !currentHistogram.name.equals(name)) {
currentHistogram = new Histogram(name, labels, line);
if (currentHistogram == null || !currentHistogram.name.equals(name)
|| !currentHistogram.labels.equals(customLabels)) {
currentHistogram = new Histogram(name, customLabels, line);
metrics.add(currentHistogram);
}
double upperBound = labels.get("le").contains("+Inf") ?
Double.MAX_VALUE : Double.parseDouble(labels.get("le"));
currentHistogram.addBucket(upperBound, value);
} else if (name.endsWith("_sum")) {
if (currentHistogram != null && currentHistogram.name.equals(name.replace("_sum", "_bucket"))) {
if (currentHistogram != null && currentHistogram.name.equals(name.replace("_sum", "_bucket"))
&& currentHistogram.labels.equals(customLabels)) {
currentHistogram.setSum(value);
} else if (currentSummary != null && currentSummary.name.equals(name.replace("_sum", ""))) {
} else if (currentSummary != null && currentSummary.name.equals(name.replace("_sum", ""))
&& currentSummary.labels.equals(customLabels)) {
currentSummary.setSum(value);
}
} else if (name.endsWith("_count")) {
if (currentHistogram != null && currentHistogram.name.equals(name.replace("_count", "_bucket"))) {
if (currentHistogram != null && currentHistogram.name.equals(name.replace("_count", "_bucket"))
&& currentHistogram.labels.equals(customLabels)) {
currentHistogram.setCount((int) value);
} else if (currentSummary != null && currentSummary.name.equals(name.replace("_count", ""))) {
} else if (currentSummary != null && currentSummary.name.equals(name.replace("_count", ""))
&& currentSummary.labels.equals(customLabels)) {
currentSummary.setCount((int) value);
} else if (type != null) {
if (type.equals("gauge")) {
metrics.add(new Gauge(name, customLabels, line, value));
} else if (type.equals("counter")) {
metrics.add(new Counter(name, customLabels, line, value));
}
}
} else if (name.contains("{quantile=")) {
if (currentSummary == null || !currentSummary.name.equals(name)) {
currentSummary = new Summary(name, labels, line);
if (currentSummary == null || !currentSummary.name.equals(name)
|| !currentSummary.labels.equals(customLabels)) {
currentSummary = new Summary(name, customLabels, line);
metrics.add(currentSummary);
}
double quantile = Double.parseDouble(labels.get("quantile"));
Expand All @@ -85,6 +107,22 @@ public static List<Metric> parse(String data) throws IOException {
return metrics;
}

/**
* Method that "removes" Prometheus labels (connected to buckets or summary) and returns just the custom labels
* provided by the user or application.
*
* @param labels parsed labels from the Prometheus metric
* @return custom labels from the metric
*/
private static Map<String, String> getCustomLabels(Map<String, String> labels) {
Map<String, String> customLabels = new HashMap<>(labels);

customLabels.remove("le");
customLabels.remove("quantile");

return customLabels;
}

private static String[] parseNameAndLabels(String metricNameAndLabels) {
int labelStartIndex = metricNameAndLabels.indexOf('{');
if (labelStartIndex == -1) {
Expand Down

0 comments on commit 7510759

Please sign in to comment.