blob: 85e0cf896a4cdb5311395b5af0d14f41ec16d149 [file] [log] [blame]
/*
* 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.solr.prometheus.exporter;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import java.util.List;
import java.util.Optional;
import java.util.regex.Matcher;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import net.thisptr.jackson.jq.JsonQuery;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.prometheus.utils.Helpers;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
public class MetricsQueryTemplateTest {
@Test
public void testTemplatesApplyDuringInit() throws Exception {
MetricsConfiguration config =
Helpers.loadConfiguration(SolrTestCaseJ4.getFile("conf/test-config-with-templates.xml").getPath());
List<MetricsQuery> metrics = config.getMetricsConfiguration();
List<JsonQuery> jsonQueries = metrics.get(0).getJsonQueries();
final int expectedJqQueriesInConfig = 6;
assertEquals(expectedJqQueriesInConfig, jsonQueries.size());
// JsonQuery does not implement an equals so use the string expression with whitespace collapsed to a single space
for (int q = 0; q < jsonQueries.size(); q += 2) {
String expected = jsonQueries.get(q + 1).toString().replaceAll("\\s+", " ").trim();
String actual = jsonQueries.get(q).toString().replaceAll("\\s+", " ").trim();
assertEquals(expected, actual);
}
}
@Test
public void testTemplateRegexMatchAndApply() {
final String[] matches = new String[]{
"$jq:jvm-item(memory_bytes,select(.key | startswith(\"memory.total.\")),object.value,\n\nGAUGE)",
"$jq:node( client_errors_total, select(.key | endswith(\".clientErrors\")), count )",
"$jq:node(time_seconds_total,\nselect(.key == \"UPDATE.updateHandler.autoCommits\"), ($object.value / 1000)) ",
"$jq:core-query( 1minRate, select(.key | endswith(\".distrib.requestTimes\")) )"
};
final String[] expectedApply = new String[]{
"memory_bytes, select(.key | startswith(\"memory.total.\")), $object.value, GAUGE",
"client_errors_total, select(.key | endswith(\".clientErrors\")), $object.value.count, COUNTER",
"time_seconds_total, select(.key == \"UPDATE.updateHandler.autoCommits\"), ($object.value / 1000), COUNTER",
"1minRate, select(.key | endswith(\".distrib.requestTimes\")), $object.value[\"1minRate\"], COUNTER"
};
MetricsQueryTemplate template =
new MetricsQueryTemplate("test", "{UNIQUE}, {KEYSELECTOR}, {METRIC}, {TYPE}", "COUNTER");
for (int m = 0; m < matches.length; m++) {
Optional<Matcher> maybeMatcher = MetricsQueryTemplate.matches(matches[m]);
assertTrue(maybeMatcher.isPresent());
String jsonQuery = template.applyTemplate(maybeMatcher.get());
assertEquals(expectedApply[m], jsonQuery);
}
}
@Test
public void testQueryMetricTemplate() throws Exception {
Document config =
DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(SolrTestCaseJ4.getFile("conf/test-config-with-templates.xml"));
NodeList jqTemplates =
(NodeList)(XPathFactory.newInstance().newXPath()).evaluate("/config/jq-templates/template", config, XPathConstants.NODESET);
assertNotNull(jqTemplates);
assertTrue(jqTemplates.getLength() > 0);
MetricsQueryTemplate coreQueryTemplate = MetricsConfiguration.loadJqTemplates(jqTemplates).get("core-query");
assertNotNull(coreQueryTemplate);
ObjectMapper objectMapper = new ObjectMapper();
JsonNode parsedMetrics = objectMapper.readTree(SolrTestCaseJ4.getFile("query-metrics.json"));
final String[] queryMetrics = new String[]{
"$jq:core-query(1minRate, select(.key | endswith(\".distrib.requestTimes\")), 1minRate)",
"$jq:core-query(p75_ms, select(.key | endswith(\".distrib.requestTimes\")), p75_ms)",
"$jq:core-query(mean_rate, select(.key | endswith(\".distrib.requestTimes\")), meanRate)",
"$jq:core-query(local_5minRate, select(.key | endswith(\".local.requestTimes\")), 5minRate)",
"$jq:core-query(local_median_ms, select(.key | endswith(\".local.requestTimes\")), median_ms)",
"$jq:core-query(local_p95_ms, select(.key | endswith(\".local.requestTimes\")), p95_ms)",
"$jq:core-query(local_count, select(.key | endswith(\".local.requestTimes\")), count, COUNTER)"
};
final double[] expectedMetrics = new double[]{
5.156897804421665,
1.31788,
0.0031956674240800156,
0.030666407244305586,
0.079579,
0.105268,
4712
};
for (int m = 0; m < queryMetrics.length; m++) {
Optional<Matcher> maybe = MetricsQueryTemplate.matches(queryMetrics[m]);
assertTrue(maybe.isPresent());
Matcher matcher = maybe.get();
JsonQuery jsonQuery = JsonQuery.compile(coreQueryTemplate.applyTemplate(matcher));
List<JsonNode> results = jsonQuery.apply(parsedMetrics);
assertNotNull(results);
assertTrue(results.size() == 1);
double value = results.get(0).get("value").doubleValue();
assertEquals(expectedMetrics[m], value, 0.0001);
}
}
}