Skip to content

Commit 49729b3

Browse files
authored
WildFly Monitoring (#224)
* Added wildfly monitoring capabilities * Updated wildfly metrics * Modified integration tests to support custom scraper builds * Updated documentation for test * Fixed mbeans in wildfly script * Updated description and removed unnecessary properties * Updated wildfly docs to include jmx url
1 parent ed5c91e commit 49729b3

File tree

9 files changed

+316
-32
lines changed

9 files changed

+316
-32
lines changed

jmx-metrics/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ mutually exclusive with `otel.jmx.groovy.script`. The currently supported target
7878
| [`kafka-producer`](./docs/target-systems/kafka-producer.md) |
7979
| [`solr`](./docs/target-systems/solr.md) |
8080
| [`tomcat`](./docs/target-systems/tomcat.md) |
81+
| [`wildfly`](./docs/target-systems/wildfly.md) |
8182

8283

8384
### JMX Query Helpers
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# WildFly Metrics
2+
3+
The JMX Metric Gatherer provides built in WildFly metric gathering capabilities.
4+
Details about using JMX with WildFly can be found here: https://docs.jboss.org/author/display/WFLY/JMX%20subsystem%20configuration.html
5+
6+
### Deployment Metrics
7+
* Name: `wildfly.session.count`
8+
* Description: The number of sessions created.
9+
* Unit: `{sessions}`
10+
* Labels: `deployment`
11+
* Instrument Type: LongCounterCallback
12+
13+
* Name: `wildfly.session.active`
14+
* Description: The number of currently active sessions.
15+
* Unit: `{sessions}`
16+
* Labels: `deployment`
17+
* Instrument Type: LongUpDownCounterCallback
18+
19+
* Name: `wildfly.session.expired`
20+
* Description: The number of sessions that have expired.
21+
* Unit: `{sessions}`
22+
* Labels: `deployment`
23+
* Instrument Type: LongCounterCallback
24+
25+
* Name: `wildfly.session.rejected`
26+
* Description: The number of sessions that have been rejected.
27+
* Unit: `{sessions}`
28+
* Labels: `deployment`
29+
* Instrument Type: LongCounterCallback
30+
31+
### Listener Metrics
32+
* Name: `wildfly.request.count`
33+
* Description: The number of requests received.
34+
* Unit: `{requests}`
35+
* Labels: `server`, `listener`
36+
* Instrument Type: LongCounterCallback
37+
38+
* Name: `wildfly.request.time`
39+
* Description: The total amount of time spent on requests.
40+
* Unit: `ns`
41+
* Labels: `server`, `listener`
42+
* Instrument Type: LongCounterCallback
43+
44+
* Name: `wildfly.request.server_error`
45+
* Description: The number of requests that have resulted in a 5xx response.
46+
* Unit: `{requests}`
47+
* Labels: `server`, `listener`
48+
* Instrument Type: LongCounterCallback
49+
50+
* Name: `wildfly.network.io`
51+
* Description: The number of bytes transmitted.
52+
* Unit: `by`
53+
* Labels: `server`, `listener`, `state`
54+
* Instrument Type: LongCounterCallback
55+
56+
### Data Source Metrics
57+
* Name: `wildfly.jdbc.connection.open`
58+
* Description: The number of open jdbc connections.
59+
* Unit: `{connections}`
60+
* Labels: `data_source`, `state`
61+
* Instrument Type: LongUpDownCounterCallback
62+
63+
* Name: `wildfly.jdbc.request.wait`
64+
* Description: The number of jdbc connections that had to wait before opening.
65+
* Unit: `{requests}`
66+
* Labels: `data_source`
67+
* Instrument Type: LongCounterCallback
68+
69+
* Name: `wildfly.jdbc.transaction.count`
70+
* Description: The number of transactions created.
71+
* Unit: `{transactions}`
72+
* Instrument Type: LongCounterCallback
73+
74+
* Name: `wildfly.jdbc.rollback.count`
75+
* Description: The number of transactions rolled back.
76+
* Unit: `{transactions}`
77+
* Instrument Type: LongCounterCallback

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

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,26 @@ void beforeAll() {
6262
otlpServer = new OtlpGrpcServer();
6363
otlpServer.start();
6464
exposeHostPorts(otlpServer.httpPort());
65+
String otlpEndpoint = "http://host.testcontainers.internal:" + otlpServer.httpPort();
6566

67+
scraper = buildScraper(otlpEndpoint);
68+
scraper.start();
69+
}
70+
71+
@AfterAll
72+
// No need to block other tests waiting on return.
73+
@SuppressWarnings("FutureReturnValueIgnored")
74+
void afterAll() {
75+
otlpServer.stop();
76+
scraper.stop();
77+
}
78+
79+
@BeforeEach
80+
void beforeEach() {
81+
otlpServer.reset();
82+
}
83+
84+
protected GenericContainer<?> buildScraper(String otlpEndpoint) {
6685
String scraperJarPath = System.getProperty("shadow.jar.path");
6786

6887
List<String> scraperCommand = new ArrayList<>();
@@ -71,9 +90,7 @@ void beforeAll() {
7190
scraperCommand.add("/app/OpenTelemetryJava.jar");
7291
scraperCommand.add("-Dotel.jmx.username=cassandra");
7392
scraperCommand.add("-Dotel.jmx.password=cassandra");
74-
scraperCommand.add(
75-
"-Dotel.exporter.otlp.endpoint=http://host.testcontainers.internal:"
76-
+ otlpServer.httpPort());
93+
scraperCommand.add("-Dotel.exporter.otlp.endpoint=" + otlpEndpoint);
7794
scraperCommand.add("io.opentelemetry.contrib.jmxmetrics.JmxMetrics");
7895
scraperCommand.add("-config");
7996

@@ -84,32 +101,17 @@ void beforeAll() {
84101
scraperCommand.add("/app/" + configName);
85102
}
86103

87-
scraper =
88-
new GenericContainer<>("openjdk:8u272-jre-slim")
89-
.withNetwork(Network.SHARED)
90-
.withCopyFileToContainer(
91-
MountableFile.forHostPath(scraperJarPath), "/app/OpenTelemetryJava.jar")
92-
.withCopyFileToContainer(
93-
MountableFile.forClasspathResource("script.groovy"), "/app/script.groovy")
94-
.withCopyFileToContainer(
95-
MountableFile.forClasspathResource(configName), "/app/" + configName)
96-
.withCommand(scraperCommand.toArray(new String[0]))
97-
.withStartupTimeout(Duration.ofMinutes(2))
98-
.waitingFor(Wait.forLogMessage(".*Started GroovyRunner.*", 1));
99-
scraper.start();
100-
}
101-
102-
@AfterAll
103-
// No need to block other tests waiting on return.
104-
@SuppressWarnings("FutureReturnValueIgnored")
105-
void afterAll() {
106-
otlpServer.stop();
107-
scraper.stop();
108-
}
109-
110-
@BeforeEach
111-
void beforeEach() {
112-
otlpServer.reset();
104+
return new GenericContainer<>("openjdk:8u272-jre-slim")
105+
.withNetwork(Network.SHARED)
106+
.withCopyFileToContainer(
107+
MountableFile.forHostPath(scraperJarPath), "/app/OpenTelemetryJava.jar")
108+
.withCopyFileToContainer(
109+
MountableFile.forClasspathResource("script.groovy"), "/app/script.groovy")
110+
.withCopyFileToContainer(
111+
MountableFile.forClasspathResource(configName), "/app/" + configName)
112+
.withCommand(scraperCommand.toArray(new String[0]))
113+
.withStartupTimeout(Duration.ofMinutes(2))
114+
.waitingFor(Wait.forLogMessage(".*Started GroovyRunner.*", 1));
113115
}
114116

115117
protected static GenericContainer<?> cassandraContainer() {
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.contrib.jmxmetrics.target_systems;
7+
8+
import static org.assertj.core.api.Assertions.entry;
9+
10+
import io.opentelemetry.contrib.jmxmetrics.AbstractIntegrationTest;
11+
import java.time.Duration;
12+
import org.junit.jupiter.api.Test;
13+
import org.testcontainers.containers.GenericContainer;
14+
import org.testcontainers.containers.Network;
15+
import org.testcontainers.containers.wait.strategy.Wait;
16+
import org.testcontainers.utility.MountableFile;
17+
18+
class WildflyIntegrationTest extends AbstractIntegrationTest {
19+
20+
WildflyIntegrationTest() {
21+
super(/* configFromStdin= */ false, "target-systems/wildfly.properties");
22+
}
23+
24+
/* In order to create a JMX connection to WildFLy, the scraper requires an additional
25+
client jar in the classpath. To facilitate this, the scraper runs in the same container,
26+
which gives it access to the client jar packaged with WildFly. */
27+
@Override
28+
protected GenericContainer<?> buildScraper(String otlpEndpoint) {
29+
String scraperJarPath = System.getProperty("shadow.jar.path");
30+
31+
return new GenericContainer<>("jboss/wildfly:23.0.1.Final")
32+
.withNetwork(Network.SHARED)
33+
.withNetworkAliases("wildfly")
34+
.withCopyFileToContainer(
35+
MountableFile.forHostPath(scraperJarPath), "/app/OpenTelemetryJMXMetrics.jar")
36+
.withCopyFileToContainer(
37+
MountableFile.forClasspathResource("script.groovy"), "/app/script.groovy")
38+
.withCopyFileToContainer(
39+
MountableFile.forClasspathResource("target-systems/wildfly.properties"),
40+
"/app/target-systems/wildfly.properties")
41+
.withCopyFileToContainer(
42+
MountableFile.forClasspathResource("wildfly/start.sh", 0007), "/app/start.sh")
43+
.withEnv("OTLP_ENDPOINT", otlpEndpoint)
44+
.withCommand("/app/start.sh")
45+
.withStartupTimeout(Duration.ofMinutes(2))
46+
.waitingFor(Wait.forLogMessage(".*Started GroovyRunner.*", 1));
47+
}
48+
49+
@Test
50+
void endToEnd() {
51+
waitAndAssertMetrics(
52+
metric ->
53+
assertSumWithAttributes(
54+
metric,
55+
"wildfly.request.count",
56+
"The number of requests received.",
57+
"{requests}",
58+
attrs ->
59+
attrs.containsOnly(
60+
entry("server", "default-server"), entry("listener", "default"))),
61+
metric ->
62+
assertSumWithAttributes(
63+
metric,
64+
"wildfly.request.time",
65+
"The total amount of time spent on requests.",
66+
"ns",
67+
attrs ->
68+
attrs.containsOnly(
69+
entry("server", "default-server"), entry("listener", "default"))),
70+
metric ->
71+
assertSumWithAttributes(
72+
metric,
73+
"wildfly.request.server_error",
74+
"The number of requests that have resulted in a 5xx response.",
75+
"{requests}",
76+
attrs ->
77+
attrs.containsOnly(
78+
entry("server", "default-server"), entry("listener", "default"))),
79+
metric ->
80+
assertSumWithAttributes(
81+
metric,
82+
"wildfly.network.io",
83+
"The number of bytes transmitted.",
84+
"by",
85+
attrs ->
86+
attrs.containsOnly(
87+
entry("server", "default-server"),
88+
entry("listener", "default"),
89+
entry("state", "in")),
90+
attrs ->
91+
attrs.containsOnly(
92+
entry("server", "default-server"),
93+
entry("listener", "default"),
94+
entry("state", "out"))),
95+
metric ->
96+
assertSumWithAttributes(
97+
metric,
98+
"wildfly.jdbc.connection.open",
99+
"The number of open jdbc connections.",
100+
"{connections}",
101+
attrs ->
102+
attrs.containsOnly(entry("data_source", "ExampleDS"), entry("state", "active")),
103+
attrs ->
104+
attrs.containsOnly(entry("data_source", "ExampleDS"), entry("state", "idle"))),
105+
metric ->
106+
assertSumWithAttributes(
107+
metric,
108+
"wildfly.jdbc.request.wait",
109+
"The number of jdbc connections that had to wait before opening.",
110+
"{requests}",
111+
attrs -> attrs.containsOnly(entry("data_source", "ExampleDS"))),
112+
metric ->
113+
assertSum(
114+
metric,
115+
"wildfly.jdbc.transaction.count",
116+
"The number of transactions created.",
117+
"{transactions}"),
118+
metric ->
119+
assertSumWithAttributes(
120+
metric,
121+
"wildfly.jdbc.rollback.count",
122+
"The number of transactions rolled back.",
123+
"{transactions}",
124+
attrs -> attrs.containsOnly(entry("cause", "system")),
125+
attrs -> attrs.containsOnly(entry("cause", "resource")),
126+
attrs -> attrs.containsOnly(entry("cause", "application"))));
127+
}
128+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
otel.jmx.interval.milliseconds = 3000
2+
otel.metrics.exporter = otlp
3+
otel.jmx.service.url = service:jmx:remote+http://wildfly:9990
4+
otel.jmx.target.system = wildfly
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/bin/sh
2+
3+
/opt/jboss/wildfly/bin/standalone.sh -b 0.0.0.0 -bmanagement 0.0.0.0 & \
4+
5+
/opt/jboss/wildfly/bin/add-user.sh user password --silent & \
6+
7+
java -cp /app/OpenTelemetryJMXMetrics.jar:/opt/jboss/wildfly/bin/client/jboss-client.jar \
8+
-Dotel.jmx.username=user -Dotel.jmx.password=password \
9+
-Dotel.exporter.otlp.endpoint=$OTLP_ENDPOINT \
10+
io.opentelemetry.contrib.jmxmetrics.JmxMetrics -config /app/target-systems/wildfly.properties

jmx-metrics/src/main/groovy/io/opentelemetry/contrib/jmxmetrics/JmxConfig.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ class JmxConfig {
4343
"kafka-consumer",
4444
"kafka-producer",
4545
"solr",
46-
"tomcat");
46+
"tomcat",
47+
"wildfly");
4748

4849
final String serviceUrl;
4950
final String groovyScript;
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
def beanWildflyDeployment = otel.mbeans("jboss.as.expr:deployment=*,subsystem=undertow")
18+
otel.instrument(beanWildflyDeployment, "wildfly.session.count", "The number of sessions created.", "{sessions}",
19+
["deployment": { mbean -> mbean.name().getKeyProperty("deployment")}],
20+
"sessionsCreated", otel.&longCounterCallback)
21+
otel.instrument(beanWildflyDeployment, "wildfly.session.active", "The number of currently active sessions.", "{sessions}",
22+
["deployment": { mbean -> mbean.name().getKeyProperty("deployment")}],
23+
"activeSessions", otel.&longUpDownCounterCallback)
24+
otel.instrument(beanWildflyDeployment, "wildfly.session.expired", "The number of sessions that have expired.", "{sessions}",
25+
["deployment": { mbean -> mbean.name().getKeyProperty("deployment")}],
26+
"expiredSessions", otel.&longCounterCallback)
27+
otel.instrument(beanWildflyDeployment, "wildfly.session.rejected", "The number of sessions that have been rejected.", "{sessions}",
28+
["deployment": { mbean -> mbean.name().getKeyProperty("deployment")}],
29+
"rejectedSessions", otel.&longCounterCallback)
30+
31+
def beanWildflyHttpListener = otel.mbeans("jboss.as:subsystem=undertow,server=*,http-listener=*")
32+
otel.instrument(beanWildflyHttpListener, "wildfly.request.count", "The number of requests received.", "{requests}",
33+
["server": { mbean -> mbean.name().getKeyProperty("server")}, "listener": { mbean -> mbean.name().getKeyProperty("http-listener")}],
34+
"requestCount", otel.&longCounterCallback)
35+
otel.instrument(beanWildflyHttpListener, "wildfly.request.time", "The total amount of time spent on requests.", "ns",
36+
["server": { mbean -> mbean.name().getKeyProperty("server")}, "listener": { mbean -> mbean.name().getKeyProperty("http-listener")}],
37+
"processingTime", otel.&longCounterCallback)
38+
otel.instrument(beanWildflyHttpListener, "wildfly.request.server_error", "The number of requests that have resulted in a 5xx response.", "{requests}",
39+
["server": { mbean -> mbean.name().getKeyProperty("server")}, "listener": { mbean -> mbean.name().getKeyProperty("http-listener")}],
40+
"errorCount", otel.&longCounterCallback)
41+
otel.instrument(beanWildflyHttpListener, "wildfly.network.io", "The number of bytes transmitted.", "by",
42+
["server": { mbean -> mbean.name().getKeyProperty("server")}, "listener": { mbean -> mbean.name().getKeyProperty("http-listener")}],
43+
["bytesSent":["state":{"out"}], "bytesReceived":["state":{"in"}]],
44+
otel.&longCounterCallback)
45+
46+
def beanWildflyDataSource = otel.mbeans("jboss.as:subsystem=datasources,data-source=*,statistics=pool")
47+
otel.instrument(beanWildflyDataSource, "wildfly.jdbc.connection.open", "The number of open jdbc connections.", "{connections}",
48+
["data_source": { mbean -> mbean.name().getKeyProperty("data-source")}],
49+
["ActiveCount":["state":{"active"}], "IdleCount":["state":{"idle"}]],
50+
otel.&longUpDownCounterCallback)
51+
otel.instrument(beanWildflyDataSource, "wildfly.jdbc.request.wait", "The number of jdbc connections that had to wait before opening.", "{requests}",
52+
["data_source": { mbean -> mbean.name().getKeyProperty("data-source")}],
53+
"WaitCount", otel.&longCounterCallback)
54+
55+
def beanWildflyTransaction = otel.mbean("jboss.as:subsystem=transactions")
56+
otel.instrument(beanWildflyTransaction, "wildfly.jdbc.transaction.count", "The number of transactions created.", "{transactions}",
57+
"numberOfTransactions", otel.&longCounterCallback)
58+
otel.instrument(beanWildflyTransaction, "wildfly.jdbc.rollback.count", "The number of transactions rolled back.", "{transactions}",
59+
["numberOfSystemRollbacks":["cause":{"system"}], "numberOfResourceRollbacks":["cause":{"resource"}], "numberOfApplicationRollbacks":["cause":{"application"}]],
60+
otel.&longCounterCallback)

0 commit comments

Comments
 (0)