Skip to content

Commit

Permalink
[jmx-scraper] add support for Solr (#1595)
Browse files Browse the repository at this point in the history
  • Loading branch information
SylvainJuge authored Dec 16, 2024
1 parent 3a16d30 commit 5257aa0
Show file tree
Hide file tree
Showing 5 changed files with 283 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,18 @@ void endToEnd() {
metric,
"solr.document.count",
"The total number of indexed documents.",
"{documents}",
"{document}",
attrs -> attrs.containsOnly(entry("core", "gettingstarted"))),
metric ->
assertSumWithAttributes(
metric,
"solr.index.size",
"The total index size.",
"by",
"By",
attrs -> attrs.containsOnly(entry("core", "gettingstarted"))),
metric ->
assertSolrRequestSumMetric(
metric, "solr.request.count", "The number of queries made.", "{queries}"),
metric, "solr.request.count", "The number of queries made.", "{query}"),
metric ->
assertSolrRequestGaugeMetric(
metric,
Expand All @@ -66,37 +66,31 @@ void endToEnd() {
metric,
"solr.request.error.count",
"The number of queries resulting in an error.",
"{queries}"),
"{query}"),
metric ->
assertSolrRequestSumMetric(
metric,
"solr.request.timeout.count",
"The number of queries resulting in a timeout.",
"{queries}"),
"{query}"),
metric ->
assertSolrCacheSumMetric(
metric,
"solr.cache.eviction.count",
"The number of evictions from a cache.",
"{evictions}"),
"{eviction}"),
metric ->
assertSolrCacheSumMetric(
metric, "solr.cache.hit.count", "The number of hits for a cache.", "{hits}"),
metric, "solr.cache.hit.count", "The number of hits for a cache.", "{hit}"),
metric ->
assertSolrCacheSumMetric(
metric,
"solr.cache.insert.count",
"The number of inserts to a cache.",
"{inserts}"),
metric, "solr.cache.insert.count", "The number of inserts to a cache.", "{insert}"),
metric ->
assertSolrCacheSumMetric(
metric,
"solr.cache.lookup.count",
"The number of lookups to a cache.",
"{lookups}"),
metric, "solr.cache.lookup.count", "The number of lookups to a cache.", "{lookup}"),
metric ->
assertSolrCacheSumMetric(
metric, "solr.cache.size", "The size of the cache occupied in memory.", "by"));
metric, "solr.cache.size", "The size of the cache occupied in memory.", "By"));
}

private void assertSolrRequestSumMetric(
Expand Down
20 changes: 10 additions & 10 deletions jmx-metrics/src/main/resources/target-systems/solr.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,18 @@
*/

def beanSolrCoreSearcherNumDocs = otel.mbeans("solr:dom1=core,dom2=*,category=SEARCHER,scope=searcher,name=numDocs")
otel.instrument(beanSolrCoreSearcherNumDocs, "solr.document.count", "The total number of indexed documents.", "{documents}",
otel.instrument(beanSolrCoreSearcherNumDocs, "solr.document.count", "The total number of indexed documents.", "{document}",
["core" : { mbean -> mbean.name().getKeyProperty("dom2") }],
"Value", otel.&longUpDownCounterCallback)

def beanSolrCoreIndexSize = otel.mbeans("solr:dom1=core,dom2=*,category=INDEX,name=sizeInBytes")
otel.instrument(beanSolrCoreIndexSize, "solr.index.size", "The total index size.", "by",
otel.instrument(beanSolrCoreIndexSize, "solr.index.size", "The total index size.", "By",
["core" : { mbean -> mbean.name().getKeyProperty("dom2") }],
"Value", otel.&longUpDownCounterCallback)

def beanSolrCoreRequests = otel.mbeans(["solr:dom1=core,dom2=*,category=QUERY,scope=*,name=requests",
"solr:dom1=core,dom2=*,category=UPDATE,scope=*,name=requests"])
otel.instrument(beanSolrCoreRequests, "solr.request.count", "The number of queries made.", "{queries}",
otel.instrument(beanSolrCoreRequests, "solr.request.count", "The number of queries made.", "{query}",
["core" : { mbean -> mbean.name().getKeyProperty("dom2") },
"type" : { mbean -> mbean.name().getKeyProperty("category") },
"handler" : { mbean -> mbean.name().getKeyProperty("scope") }],
Expand All @@ -44,38 +44,38 @@ otel.instrument(beanSolrCoreRequestTimes, "solr.request.time.average",

def beanSolrCoreErrors = otel.mbeans(["solr:dom1=core,dom2=*,category=QUERY,scope=*,name=errors",
"solr:dom1=core,dom2=*,category=UPDATE,scope=*,name=errors"])
otel.instrument(beanSolrCoreErrors, "solr.request.error.count", "The number of queries resulting in an error.", "{queries}",
otel.instrument(beanSolrCoreErrors, "solr.request.error.count", "The number of queries resulting in an error.", "{query}",
["core" : { mbean -> mbean.name().getKeyProperty("dom2") },
"type" : { mbean -> mbean.name().getKeyProperty("category") },
"handler" : { mbean -> mbean.name().getKeyProperty("scope") }],
"Count", otel.&longCounterCallback)

def beanSolrCoreTimeouts = otel.mbeans(["solr:dom1=core,dom2=*,category=QUERY,scope=*,name=timeouts",
"solr:dom1=core,dom2=*,category=UPDATE,scope=*,name=timeouts"])
otel.instrument(beanSolrCoreTimeouts, "solr.request.timeout.count", "The number of queries resulting in a timeout.", "{queries}",
otel.instrument(beanSolrCoreTimeouts, "solr.request.timeout.count", "The number of queries resulting in a timeout.", "{query}",
["core" : { mbean -> mbean.name().getKeyProperty("dom2") },
"type" : { mbean -> mbean.name().getKeyProperty("category") },
"handler" : { mbean -> mbean.name().getKeyProperty("scope") }],
"Count", otel.&longCounterCallback)

def beanSolrCoreQueryResultsCache = otel.mbeans("solr:dom1=core,dom2=*,category=CACHE,scope=*,name=queryResultCache")
otel.instrument(beanSolrCoreQueryResultsCache, "solr.cache.eviction.count", "The number of evictions from a cache.", "{evictions}",
otel.instrument(beanSolrCoreQueryResultsCache, "solr.cache.eviction.count", "The number of evictions from a cache.", "{eviction}",
["core" : { mbean -> mbean.name().getKeyProperty("dom2") },
"cache" : { mbean -> mbean.name().getKeyProperty("scope") }],
"cumulative_evictions", otel.&longCounterCallback)
otel.instrument(beanSolrCoreQueryResultsCache, "solr.cache.hit.count", "The number of hits for a cache.", "{hits}",
otel.instrument(beanSolrCoreQueryResultsCache, "solr.cache.hit.count", "The number of hits for a cache.", "{hit}",
["core" : { mbean -> mbean.name().getKeyProperty("dom2") },
"cache" : { mbean -> mbean.name().getKeyProperty("scope") }],
"cumulative_hits", otel.&longCounterCallback)
otel.instrument(beanSolrCoreQueryResultsCache, "solr.cache.insert.count", "The number of inserts to a cache.", "{inserts}",
otel.instrument(beanSolrCoreQueryResultsCache, "solr.cache.insert.count", "The number of inserts to a cache.", "{insert}",
["core" : { mbean -> mbean.name().getKeyProperty("dom2") },
"cache" : { mbean -> mbean.name().getKeyProperty("scope") }],
"cumulative_inserts", otel.&longCounterCallback)
otel.instrument(beanSolrCoreQueryResultsCache, "solr.cache.lookup.count", "The number of lookups to a cache.", "{lookups}",
otel.instrument(beanSolrCoreQueryResultsCache, "solr.cache.lookup.count", "The number of lookups to a cache.", "{lookup}",
["core" : { mbean -> mbean.name().getKeyProperty("dom2") },
"cache" : { mbean -> mbean.name().getKeyProperty("scope") }],
"cumulative_lookups", otel.&longCounterCallback)
otel.instrument(beanSolrCoreQueryResultsCache, "solr.cache.size", "The size of the cache occupied in memory.", "by",
otel.instrument(beanSolrCoreQueryResultsCache, "solr.cache.size", "The size of the cache occupied in memory.", "By",
["core" : { mbean -> mbean.name().getKeyProperty("dom2") },
"cache" : { mbean -> mbean.name().getKeyProperty("scope") }],
"ramBytesUsed", otel.&longUpDownCounterCallback)
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.contrib.jmxscraper.target_systems;

import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attribute;
import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attributeGroup;
import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attributeWithAnyValue;

import io.opentelemetry.contrib.jmxscraper.JmxScraperContainer;
import io.opentelemetry.contrib.jmxscraper.assertions.AttributeMatcher;
import io.opentelemetry.contrib.jmxscraper.assertions.AttributeMatcherGroup;
import java.nio.file.Path;
import java.time.Duration;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;

public class SolrIntegrationTest extends TargetSystemIntegrationTest {

@Override
protected GenericContainer<?> createTargetContainer(int jmxPort) {
return new GenericContainer<>("solr:8.8.2")
.withNetwork(Network.SHARED)
.withEnv("LOCAL_JMX", "no")
.withEnv("ENABLE_REMOTE_JMX_OPTS", "true")
.withEnv("RMI_PORT", Integer.toString(jmxPort))
.withCommand("solr-precreate", "gettingstarted")
.withExposedPorts(jmxPort)
.withStartupTimeout(Duration.ofMinutes(2))
.waitingFor(Wait.forListeningPort());
}

@Override
protected JmxScraperContainer customizeScraperContainer(
JmxScraperContainer scraper, GenericContainer<?> target, Path tempDir) {
return scraper.withTargetSystem("solr");
}

@Override
protected MetricsVerifier createMetricsVerifier() {

AttributeMatcher coreAttribute = attribute("core", "gettingstarted");
AttributeMatcherGroup[] requestAttributes = requestAttributes(coreAttribute);
AttributeMatcherGroup cacheAttributes =
attributeGroup(coreAttribute, attribute("cache", "searcher"));

return MetricsVerifier.create()
.add(
"solr.document.count",
metric ->
metric
.hasDescription("The total number of indexed documents.")
.hasUnit("{document}")
.isUpDownCounter()
.hasDataPointsWithOneAttribute(coreAttribute))
.add(
"solr.index.size",
metric ->
metric
.hasDescription("The total index size.")
.hasUnit("By")
.isUpDownCounter()
.hasDataPointsWithOneAttribute(coreAttribute))
.add(
"solr.request.count",
metric ->
metric
.hasDescription("The number of queries made.")
.hasUnit("{query}")
.isCounter()
.hasDataPointsWithAttributes(requestAttributes))
.add(
"solr.request.time.average",
metric ->
metric
.hasDescription(
"The average time of a query, based on Solr's histogram configuration.")
.hasUnit("ms")
.isGauge()
.hasDataPointsWithAttributes(requestAttributes))
.add(
"solr.request.error.count",
metric ->
metric
.hasDescription("The number of queries resulting in an error.")
.hasUnit("{query}")
.isCounter()
.hasDataPointsWithAttributes(requestAttributes))
.add(
"solr.request.timeout.count",
metric ->
metric
.hasDescription("The number of queries resulting in a timeout.")
.hasUnit("{query}")
.isCounter()
.hasDataPointsWithAttributes(requestAttributes))
.add(
"solr.cache.eviction.count",
metric ->
metric
.hasDescription("The number of evictions from a cache.")
.hasUnit("{eviction}")
.isCounter()
.hasDataPointsWithAttributes(cacheAttributes))
.add(
"solr.cache.hit.count",
metric ->
metric
.hasDescription("The number of hits for a cache.")
.hasUnit("{hit}")
.isCounter()
.hasDataPointsWithAttributes(cacheAttributes))
.add(
"solr.cache.insert.count",
metric ->
metric
.hasDescription("The number of inserts to a cache.")
.hasUnit("{insert}")
.isCounter()
.hasDataPointsWithAttributes(cacheAttributes))
.add(
"solr.cache.lookup.count",
metric ->
metric
.hasDescription("The number of lookups to a cache.")
.hasUnit("{lookup}")
.isCounter()
.hasDataPointsWithAttributes(cacheAttributes))
.add(
"solr.cache.size",
metric ->
metric
.hasDescription("The size of the cache occupied in memory.")
.hasUnit("By")
.isUpDownCounter()
.hasDataPointsWithAttributes(cacheAttributes));
}

private static AttributeMatcherGroup[] requestAttributes(AttributeMatcher coreAttribute) {
// ignore actual 'handler' values due to high cardinality (10+) and an exact matching makes test
// flaky
return new AttributeMatcherGroup[] {
attributeGroup(coreAttribute, attributeWithAnyValue("handler"), attribute("type", "QUERY")),
attributeGroup(coreAttribute, attributeWithAnyValue("handler"), attribute("type", "UPDATE"))
};
}
}
6 changes: 3 additions & 3 deletions jmx-scraper/src/main/resources/jvm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ rules:
LoadedClassCount:
metric: jvm.classes.loaded
type: gauge
unit: '{class}'
unit: "{class}"
desc: number of loaded classes

- bean: java.lang:type=GarbageCollector,name=*
mapping:
CollectionCount:
metric: jvm.gc.collections.count
type: counter
unit: '{collection}'
unit: "{collection}"
desc: total number of collections that have occurred
metricAttribute:
name: param(name)
Expand Down Expand Up @@ -87,5 +87,5 @@ rules:
mapping:
ThreadCount:
metric: jvm.threads.count
unit: '{thread}'
unit: "{thread}"
desc: number of threads
Loading

0 comments on commit 5257aa0

Please sign in to comment.