Skip to content

Commit 5257aa0

Browse files
authored
[jmx-scraper] add support for Solr (#1595)
1 parent 3a16d30 commit 5257aa0

File tree

5 files changed

+283
-29
lines changed

5 files changed

+283
-29
lines changed

jmx-metrics/src/integrationTest/java/io/opentelemetry/contrib/jmxmetrics/target_systems/SolrIntegrationTest.java

+10-16
Original file line numberDiff line numberDiff line change
@@ -43,18 +43,18 @@ void endToEnd() {
4343
metric,
4444
"solr.document.count",
4545
"The total number of indexed documents.",
46-
"{documents}",
46+
"{document}",
4747
attrs -> attrs.containsOnly(entry("core", "gettingstarted"))),
4848
metric ->
4949
assertSumWithAttributes(
5050
metric,
5151
"solr.index.size",
5252
"The total index size.",
53-
"by",
53+
"By",
5454
attrs -> attrs.containsOnly(entry("core", "gettingstarted"))),
5555
metric ->
5656
assertSolrRequestSumMetric(
57-
metric, "solr.request.count", "The number of queries made.", "{queries}"),
57+
metric, "solr.request.count", "The number of queries made.", "{query}"),
5858
metric ->
5959
assertSolrRequestGaugeMetric(
6060
metric,
@@ -66,37 +66,31 @@ void endToEnd() {
6666
metric,
6767
"solr.request.error.count",
6868
"The number of queries resulting in an error.",
69-
"{queries}"),
69+
"{query}"),
7070
metric ->
7171
assertSolrRequestSumMetric(
7272
metric,
7373
"solr.request.timeout.count",
7474
"The number of queries resulting in a timeout.",
75-
"{queries}"),
75+
"{query}"),
7676
metric ->
7777
assertSolrCacheSumMetric(
7878
metric,
7979
"solr.cache.eviction.count",
8080
"The number of evictions from a cache.",
81-
"{evictions}"),
81+
"{eviction}"),
8282
metric ->
8383
assertSolrCacheSumMetric(
84-
metric, "solr.cache.hit.count", "The number of hits for a cache.", "{hits}"),
84+
metric, "solr.cache.hit.count", "The number of hits for a cache.", "{hit}"),
8585
metric ->
8686
assertSolrCacheSumMetric(
87-
metric,
88-
"solr.cache.insert.count",
89-
"The number of inserts to a cache.",
90-
"{inserts}"),
87+
metric, "solr.cache.insert.count", "The number of inserts to a cache.", "{insert}"),
9188
metric ->
9289
assertSolrCacheSumMetric(
93-
metric,
94-
"solr.cache.lookup.count",
95-
"The number of lookups to a cache.",
96-
"{lookups}"),
90+
metric, "solr.cache.lookup.count", "The number of lookups to a cache.", "{lookup}"),
9791
metric ->
9892
assertSolrCacheSumMetric(
99-
metric, "solr.cache.size", "The size of the cache occupied in memory.", "by"));
93+
metric, "solr.cache.size", "The size of the cache occupied in memory.", "By"));
10094
}
10195

10296
private void assertSolrRequestSumMetric(

jmx-metrics/src/main/resources/target-systems/solr.groovy

+10-10
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,18 @@
1515
*/
1616

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

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

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

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

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

6161
def beanSolrCoreQueryResultsCache = otel.mbeans("solr:dom1=core,dom2=*,category=CACHE,scope=*,name=queryResultCache")
62-
otel.instrument(beanSolrCoreQueryResultsCache, "solr.cache.eviction.count", "The number of evictions from a cache.", "{evictions}",
62+
otel.instrument(beanSolrCoreQueryResultsCache, "solr.cache.eviction.count", "The number of evictions from a cache.", "{eviction}",
6363
["core" : { mbean -> mbean.name().getKeyProperty("dom2") },
6464
"cache" : { mbean -> mbean.name().getKeyProperty("scope") }],
6565
"cumulative_evictions", otel.&longCounterCallback)
66-
otel.instrument(beanSolrCoreQueryResultsCache, "solr.cache.hit.count", "The number of hits for a cache.", "{hits}",
66+
otel.instrument(beanSolrCoreQueryResultsCache, "solr.cache.hit.count", "The number of hits for a cache.", "{hit}",
6767
["core" : { mbean -> mbean.name().getKeyProperty("dom2") },
6868
"cache" : { mbean -> mbean.name().getKeyProperty("scope") }],
6969
"cumulative_hits", otel.&longCounterCallback)
70-
otel.instrument(beanSolrCoreQueryResultsCache, "solr.cache.insert.count", "The number of inserts to a cache.", "{inserts}",
70+
otel.instrument(beanSolrCoreQueryResultsCache, "solr.cache.insert.count", "The number of inserts to a cache.", "{insert}",
7171
["core" : { mbean -> mbean.name().getKeyProperty("dom2") },
7272
"cache" : { mbean -> mbean.name().getKeyProperty("scope") }],
7373
"cumulative_inserts", otel.&longCounterCallback)
74-
otel.instrument(beanSolrCoreQueryResultsCache, "solr.cache.lookup.count", "The number of lookups to a cache.", "{lookups}",
74+
otel.instrument(beanSolrCoreQueryResultsCache, "solr.cache.lookup.count", "The number of lookups to a cache.", "{lookup}",
7575
["core" : { mbean -> mbean.name().getKeyProperty("dom2") },
7676
"cache" : { mbean -> mbean.name().getKeyProperty("scope") }],
7777
"cumulative_lookups", otel.&longCounterCallback)
78-
otel.instrument(beanSolrCoreQueryResultsCache, "solr.cache.size", "The size of the cache occupied in memory.", "by",
78+
otel.instrument(beanSolrCoreQueryResultsCache, "solr.cache.size", "The size of the cache occupied in memory.", "By",
7979
["core" : { mbean -> mbean.name().getKeyProperty("dom2") },
8080
"cache" : { mbean -> mbean.name().getKeyProperty("scope") }],
8181
"ramBytesUsed", otel.&longUpDownCounterCallback)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.contrib.jmxscraper.target_systems;
7+
8+
import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attribute;
9+
import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attributeGroup;
10+
import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attributeWithAnyValue;
11+
12+
import io.opentelemetry.contrib.jmxscraper.JmxScraperContainer;
13+
import io.opentelemetry.contrib.jmxscraper.assertions.AttributeMatcher;
14+
import io.opentelemetry.contrib.jmxscraper.assertions.AttributeMatcherGroup;
15+
import java.nio.file.Path;
16+
import java.time.Duration;
17+
import org.testcontainers.containers.GenericContainer;
18+
import org.testcontainers.containers.Network;
19+
import org.testcontainers.containers.wait.strategy.Wait;
20+
21+
public class SolrIntegrationTest extends TargetSystemIntegrationTest {
22+
23+
@Override
24+
protected GenericContainer<?> createTargetContainer(int jmxPort) {
25+
return new GenericContainer<>("solr:8.8.2")
26+
.withNetwork(Network.SHARED)
27+
.withEnv("LOCAL_JMX", "no")
28+
.withEnv("ENABLE_REMOTE_JMX_OPTS", "true")
29+
.withEnv("RMI_PORT", Integer.toString(jmxPort))
30+
.withCommand("solr-precreate", "gettingstarted")
31+
.withExposedPorts(jmxPort)
32+
.withStartupTimeout(Duration.ofMinutes(2))
33+
.waitingFor(Wait.forListeningPort());
34+
}
35+
36+
@Override
37+
protected JmxScraperContainer customizeScraperContainer(
38+
JmxScraperContainer scraper, GenericContainer<?> target, Path tempDir) {
39+
return scraper.withTargetSystem("solr");
40+
}
41+
42+
@Override
43+
protected MetricsVerifier createMetricsVerifier() {
44+
45+
AttributeMatcher coreAttribute = attribute("core", "gettingstarted");
46+
AttributeMatcherGroup[] requestAttributes = requestAttributes(coreAttribute);
47+
AttributeMatcherGroup cacheAttributes =
48+
attributeGroup(coreAttribute, attribute("cache", "searcher"));
49+
50+
return MetricsVerifier.create()
51+
.add(
52+
"solr.document.count",
53+
metric ->
54+
metric
55+
.hasDescription("The total number of indexed documents.")
56+
.hasUnit("{document}")
57+
.isUpDownCounter()
58+
.hasDataPointsWithOneAttribute(coreAttribute))
59+
.add(
60+
"solr.index.size",
61+
metric ->
62+
metric
63+
.hasDescription("The total index size.")
64+
.hasUnit("By")
65+
.isUpDownCounter()
66+
.hasDataPointsWithOneAttribute(coreAttribute))
67+
.add(
68+
"solr.request.count",
69+
metric ->
70+
metric
71+
.hasDescription("The number of queries made.")
72+
.hasUnit("{query}")
73+
.isCounter()
74+
.hasDataPointsWithAttributes(requestAttributes))
75+
.add(
76+
"solr.request.time.average",
77+
metric ->
78+
metric
79+
.hasDescription(
80+
"The average time of a query, based on Solr's histogram configuration.")
81+
.hasUnit("ms")
82+
.isGauge()
83+
.hasDataPointsWithAttributes(requestAttributes))
84+
.add(
85+
"solr.request.error.count",
86+
metric ->
87+
metric
88+
.hasDescription("The number of queries resulting in an error.")
89+
.hasUnit("{query}")
90+
.isCounter()
91+
.hasDataPointsWithAttributes(requestAttributes))
92+
.add(
93+
"solr.request.timeout.count",
94+
metric ->
95+
metric
96+
.hasDescription("The number of queries resulting in a timeout.")
97+
.hasUnit("{query}")
98+
.isCounter()
99+
.hasDataPointsWithAttributes(requestAttributes))
100+
.add(
101+
"solr.cache.eviction.count",
102+
metric ->
103+
metric
104+
.hasDescription("The number of evictions from a cache.")
105+
.hasUnit("{eviction}")
106+
.isCounter()
107+
.hasDataPointsWithAttributes(cacheAttributes))
108+
.add(
109+
"solr.cache.hit.count",
110+
metric ->
111+
metric
112+
.hasDescription("The number of hits for a cache.")
113+
.hasUnit("{hit}")
114+
.isCounter()
115+
.hasDataPointsWithAttributes(cacheAttributes))
116+
.add(
117+
"solr.cache.insert.count",
118+
metric ->
119+
metric
120+
.hasDescription("The number of inserts to a cache.")
121+
.hasUnit("{insert}")
122+
.isCounter()
123+
.hasDataPointsWithAttributes(cacheAttributes))
124+
.add(
125+
"solr.cache.lookup.count",
126+
metric ->
127+
metric
128+
.hasDescription("The number of lookups to a cache.")
129+
.hasUnit("{lookup}")
130+
.isCounter()
131+
.hasDataPointsWithAttributes(cacheAttributes))
132+
.add(
133+
"solr.cache.size",
134+
metric ->
135+
metric
136+
.hasDescription("The size of the cache occupied in memory.")
137+
.hasUnit("By")
138+
.isUpDownCounter()
139+
.hasDataPointsWithAttributes(cacheAttributes));
140+
}
141+
142+
private static AttributeMatcherGroup[] requestAttributes(AttributeMatcher coreAttribute) {
143+
// ignore actual 'handler' values due to high cardinality (10+) and an exact matching makes test
144+
// flaky
145+
return new AttributeMatcherGroup[] {
146+
attributeGroup(coreAttribute, attributeWithAnyValue("handler"), attribute("type", "QUERY")),
147+
attributeGroup(coreAttribute, attributeWithAnyValue("handler"), attribute("type", "UPDATE"))
148+
};
149+
}
150+
}

jmx-scraper/src/main/resources/jvm.yaml

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ rules:
77
LoadedClassCount:
88
metric: jvm.classes.loaded
99
type: gauge
10-
unit: '{class}'
10+
unit: "{class}"
1111
desc: number of loaded classes
1212

1313
- bean: java.lang:type=GarbageCollector,name=*
1414
mapping:
1515
CollectionCount:
1616
metric: jvm.gc.collections.count
1717
type: counter
18-
unit: '{collection}'
18+
unit: "{collection}"
1919
desc: total number of collections that have occurred
2020
metricAttribute:
2121
name: param(name)
@@ -87,5 +87,5 @@ rules:
8787
mapping:
8888
ThreadCount:
8989
metric: jvm.threads.count
90-
unit: '{thread}'
90+
unit: "{thread}"
9191
desc: number of threads

0 commit comments

Comments
 (0)