Skip to content

Commit 7f7681b

Browse files
committed
first working poc with tomcat
1 parent 5948f57 commit 7f7681b

File tree

3 files changed

+160
-22
lines changed

3 files changed

+160
-22
lines changed

jmx-scraper/build.gradle.kts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ dependencies {
3333
implementation("io.opentelemetry:opentelemetry-sdk-metrics")
3434
implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
3535

36+
runtimeOnly("io.opentelemetry:opentelemetry-exporter-otlp")
37+
runtimeOnly("io.opentelemetry:opentelemetry-exporter-logging")
38+
3639
implementation("io.opentelemetry.instrumentation:opentelemetry-jmx-metrics")
3740

3841
testImplementation("org.junit-pioneer:junit-pioneer")

jmx-scraper/src/main/java/io/opentelemetry/contrib/jmxscraper/JmxScraper.java

Lines changed: 73 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,22 @@
55

66
package io.opentelemetry.contrib.jmxscraper;
77

8+
import io.opentelemetry.api.GlobalOpenTelemetry;
89
import io.opentelemetry.contrib.jmxscraper.config.ConfigurationException;
910
import io.opentelemetry.contrib.jmxscraper.config.JmxScraperConfig;
11+
import io.opentelemetry.instrumentation.jmx.engine.JmxMetricInsight;
12+
import io.opentelemetry.instrumentation.jmx.engine.MetricConfiguration;
13+
import io.opentelemetry.instrumentation.jmx.yaml.RuleParser;
1014
import java.io.DataInputStream;
1115
import java.io.IOException;
1216
import java.io.InputStream;
1317
import java.nio.file.Files;
1418
import java.nio.file.Paths;
1519
import java.util.Arrays;
20+
import java.util.Collections;
1621
import java.util.List;
1722
import java.util.Properties;
23+
import java.util.concurrent.atomic.AtomicBoolean;
1824
import java.util.logging.Logger;
1925
import javax.management.MBeanServerConnection;
2026
import javax.management.remote.JMXConnector;
@@ -23,10 +29,13 @@ public class JmxScraper {
2329
private static final Logger logger = Logger.getLogger(JmxScraper.class.getName());
2430
private static final String CONFIG_ARG = "-config";
2531

32+
private static final String OTEL_AUTOCONFIGURE = "otel.java.global-autoconfigure.enabled";
33+
2634
private final JmxConnectorBuilder client;
35+
private final JmxMetricInsight service;
36+
private final JmxScraperConfig config;
2737

28-
// TODO depend on instrumentation 2.9.0 snapshot
29-
// private final JmxMetricInsight service;
38+
private final AtomicBoolean running = new AtomicBoolean(false);
3039

3140
/**
3241
* Main method to create and run a {@link JmxScraper} instance.
@@ -35,15 +44,23 @@ public class JmxScraper {
3544
*/
3645
@SuppressWarnings({"SystemOut", "SystemExitOutsideMain"})
3746
public static void main(String[] args) {
47+
48+
// enable SDK auto-configure if not explicitly set by user
49+
if (System.getProperty(OTEL_AUTOCONFIGURE) == null) {
50+
System.setProperty(OTEL_AUTOCONFIGURE, "true");
51+
}
52+
3853
try {
3954
JmxScraperConfig config =
4055
JmxScraperConfig.fromProperties(parseArgs(Arrays.asList(args)), System.getProperties());
4156
// propagate effective user-provided configuration to JVM system properties
57+
// this also enables SDK auto-configuration to use those properties
4258
config.propagateSystemProperties();
43-
// TODO: depend on instrumentation 2.9.0 snapshot
44-
// service = JmxMetricInsight.createService(GlobalOpenTelemetry.get(),
45-
// config.getIntervalMilliseconds());
46-
JmxScraper jmxScraper = new JmxScraper(JmxConnectorBuilder.createNew(config.getServiceUrl()));
59+
60+
JmxMetricInsight service = JmxMetricInsight.createService(GlobalOpenTelemetry.get(),
61+
config.getIntervalMilliseconds());
62+
JmxScraper jmxScraper = new JmxScraper(JmxConnectorBuilder.createNew(config.getServiceUrl()),
63+
service, config);
4764
jmxScraper.start();
4865

4966
} catch (ArgumentsParsingException e) {
@@ -109,29 +126,63 @@ private static Properties loadPropertiesFromPath(String path) throws Configurati
109126
}
110127
}
111128

112-
JmxScraper(JmxConnectorBuilder client) {
129+
JmxScraper(JmxConnectorBuilder client, JmxMetricInsight service, JmxScraperConfig config) {
113130
this.client = client;
131+
this.service = service;
132+
this.config = config;
114133
}
115134

116135
private void start() throws IOException {
136+
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
137+
logger.info("JMX scraping stopped");
138+
running.set(false);
139+
}));
140+
141+
try (JMXConnector connector = client.build()) {
142+
MBeanServerConnection connection = connector.getMBeanServerConnection();
143+
service.startRemote(getMetricConfig(config), () -> Collections.singletonList(connection));
144+
145+
running.set(true);
146+
logger.info("JMX scraping started");
147+
148+
while (running.get()) {
149+
try {
150+
Thread.sleep(100);
151+
} catch (InterruptedException e) {
152+
// silenty ignored
153+
}
154+
}
155+
}
156+
}
117157

118-
JMXConnector connector = client.build();
119-
120-
@SuppressWarnings("unused")
121-
MBeanServerConnection connection = connector.getMBeanServerConnection();
122-
123-
// TODO: depend on instrumentation 2.9.0 snapshot
124-
// MetricConfiguration metricConfig = new MetricConfiguration();
125-
// TODO create JMX insight config from scraper config
126-
// service.startRemote(metricConfig, () -> Collections.singletonList(connection));
158+
private static MetricConfiguration getMetricConfig(JmxScraperConfig scraperConfig) {
159+
MetricConfiguration config = new MetricConfiguration();
160+
for (String system : scraperConfig.getTargetSystems()) {
161+
try {
162+
addRulesForSystem(system, config);
163+
} catch (RuntimeException e) {
164+
logger.warning("unable to load rules for system " + system + ": " + e.getMessage());
165+
}
166+
}
167+
// TODO : add ability for user to provide custom yaml configurations
127168

128-
logger.info("JMX scraping started");
169+
return config;
170+
}
129171

130-
// TODO: wait a bit to keep the JVM running, this won't be needed once calling jmx insight
131-
try {
132-
Thread.sleep(5000);
133-
} catch (InterruptedException e) {
134-
throw new IllegalStateException(e);
172+
private static void addRulesForSystem(String system, MetricConfiguration conf) {
173+
String yamlResource = system + ".yaml";
174+
try (InputStream inputStream =
175+
JmxScraper.class.getClassLoader().getResourceAsStream(yamlResource)) {
176+
if (inputStream != null) {
177+
RuleParser parserInstance = RuleParser.get();
178+
parserInstance.addMetricDefsTo(conf, inputStream, system);
179+
} else {
180+
throw new IllegalStateException("no support for " + system);
181+
}
182+
} catch (Exception e) {
183+
throw new IllegalStateException("error while loading rules for system " + system, e);
135184
}
136185
}
186+
187+
137188
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
---
2+
3+
### TODO: for now this is a copy of tomcat.yaml from instrumentation
4+
### This is only for testing and does not fit the current metrics definitions of JMX Gatherer
5+
###
6+
7+
# For Tomcat, the default JMX domain is "Catalina:", however with some deployments like embedded in spring-boot
8+
# we can have the "Tomcat:" domain used, thus we use both MBean names for the metrics.
9+
10+
rules:
11+
- beans:
12+
- Catalina:type=GlobalRequestProcessor,name=*
13+
- Tomcat:type=GlobalRequestProcessor,name=*
14+
unit: "1"
15+
prefix: http.server.tomcat.
16+
metricAttribute:
17+
name: param(name)
18+
mapping:
19+
errorCount:
20+
metric: errorCount
21+
type: gauge
22+
desc: The number of errors per second on all request processors
23+
requestCount:
24+
metric: requestCount
25+
type: gauge
26+
desc: The number of requests per second across all request processors
27+
maxTime:
28+
metric: maxTime
29+
type: gauge
30+
unit: ms
31+
desc: The longest request processing time
32+
processingTime:
33+
metric: processingTime
34+
type: counter
35+
unit: ms
36+
desc: Total time for processing all requests
37+
bytesReceived:
38+
metric: traffic
39+
type: counter
40+
unit: By
41+
desc: The number of bytes transmitted
42+
metricAttribute:
43+
direction: const(received)
44+
bytesSent:
45+
metric: traffic
46+
type: counter
47+
unit: By
48+
desc: The number of bytes transmitted
49+
metricAttribute:
50+
direction: const(sent)
51+
52+
- beans:
53+
- Catalina:type=Manager,host=localhost,context=*
54+
- Tomcat:type=Manager,host=localhost,context=*
55+
unit: "1"
56+
prefix: http.server.tomcat.
57+
type: updowncounter
58+
metricAttribute:
59+
context: param(context)
60+
mapping:
61+
activeSessions:
62+
metric: sessions.activeSessions
63+
desc: The number of active sessions
64+
65+
- beans:
66+
- Catalina:type=ThreadPool,name=*
67+
- Tomcat:type=ThreadPool,name=*
68+
unit: "{threads}"
69+
prefix: http.server.tomcat.
70+
type: updowncounter
71+
metricAttribute:
72+
name: param(name)
73+
mapping:
74+
currentThreadCount:
75+
metric: threads
76+
desc: Thread Count of the Thread Pool
77+
metricAttribute:
78+
state: const(idle)
79+
currentThreadsBusy:
80+
metric: threads
81+
desc: Thread Count of the Thread Pool
82+
metricAttribute:
83+
state: const(busy)
84+

0 commit comments

Comments
 (0)