From f2cfd9d211d46bdfcb536920d9a0ac5ca6c35395 Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Tue, 27 May 2025 09:41:29 +0200 Subject: [PATCH 01/15] move jetty definition to library --- instrumentation/jmx-metrics/README.md | 2 +- instrumentation/jmx-metrics/{javaagent => library}/jetty.md | 0 .../src/main/resources/jmx/rules/jetty.yaml | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename instrumentation/jmx-metrics/{javaagent => library}/jetty.md (100%) rename instrumentation/jmx-metrics/{javaagent => library}/src/main/resources/jmx/rules/jetty.yaml (100%) diff --git a/instrumentation/jmx-metrics/README.md b/instrumentation/jmx-metrics/README.md index 502ebe8bb5e9..0e008cccd6bc 100644 --- a/instrumentation/jmx-metrics/README.md +++ b/instrumentation/jmx-metrics/README.md @@ -27,7 +27,7 @@ No targets are enabled by default. The supported target environments are listed - [activemq](javaagent/activemq.md) - [camel](javaagent/camel.md) -- [jetty](javaagent/jetty.md) +- [jetty](library/jetty.md) - [kafka-broker](javaagent/kafka-broker.md) - [tomcat](javaagent/tomcat.md) - [wildfly](javaagent/wildfly.md) diff --git a/instrumentation/jmx-metrics/javaagent/jetty.md b/instrumentation/jmx-metrics/library/jetty.md similarity index 100% rename from instrumentation/jmx-metrics/javaagent/jetty.md rename to instrumentation/jmx-metrics/library/jetty.md diff --git a/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/jetty.yaml b/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml similarity index 100% rename from instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/jetty.yaml rename to instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml From cb29b8f14d5a207f59b68de93dbbabae5343729e Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Tue, 17 Jun 2025 13:34:41 +0200 Subject: [PATCH 02/15] add jetty integration test --- .../jmx/JmxMetricInsightInstallerTest.java | 1 - .../jmx/rules/JettyIntegrationTest.java | 65 +++++++++++++++++++ .../jmx/rules/TomcatIntegrationTest.java | 1 - 3 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java diff --git a/instrumentation/jmx-metrics/javaagent/src/test/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstallerTest.java b/instrumentation/jmx-metrics/javaagent/src/test/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstallerTest.java index 88d8d6787357..baa5fab88abd 100644 --- a/instrumentation/jmx-metrics/javaagent/src/test/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstallerTest.java +++ b/instrumentation/jmx-metrics/javaagent/src/test/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstallerTest.java @@ -36,7 +36,6 @@ class JmxMetricInsightInstallerTest { "activemq.yaml", "camel.yaml", "hadoop.yaml", - "jetty.yaml", "kafka-broker.yaml", "wildfly.yaml")); diff --git a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java new file mode 100644 index 000000000000..03fee02b1e95 --- /dev/null +++ b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java @@ -0,0 +1,65 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.jmx.rules; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.images.builder.ImageFromDockerfile; + +public class JettyIntegrationTest extends TargetSystemTest { + + // TODO: test with multiple versions + + private static final String DOCKER_IMAGE = "jetty:11"; + private static final int JETTY_PORT = 8080; + + @Test + void testCollectedMetrics() { + + List yamlFiles = Collections.singletonList("jetty.yaml"); + + yamlFiles.forEach(this::validateYamlSyntax); + + List jvmArgs = new ArrayList<>(); + jvmArgs.add(javaAgentJvmArgument()); + jvmArgs.addAll(javaPropertiesToJvmArgs(otelConfigProperties(yamlFiles))); + + GenericContainer container = + new GenericContainer<>( + new ImageFromDockerfile() + .withDockerfileFromBuilder( + builder -> + builder + .from(DOCKER_IMAGE) + .run( + "java", + "-jar", + "/usr/local/jetty/start.jar", + "--add-to-startd=jmx,stats,http") + .run("mkdir -p /var/lib/jetty/webapps/ROOT/") + .run("touch /var/lib/jetty/webapps/ROOT/index.html") + .build())) + .withEnv("JAVA_OPTIONS", String.join(" ", jvmArgs)) + .withStartupTimeout(Duration.ofMinutes(2)) + .withExposedPorts(JETTY_PORT) + .waitingFor(Wait.forListeningPorts(JETTY_PORT)); + + copyFilesToTarget(container, yamlFiles); + + startTarget(container); + + verifyMetrics(createMetricsVerifier()); + } + + private static MetricsVerifier createMetricsVerifier() { + return MetricsVerifier.create().add("jetty.dummy.metric", metric -> metric.hasDescription("hello")); + } +} diff --git a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/TomcatIntegrationTest.java b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/TomcatIntegrationTest.java index 1ab0ab097915..f55946785191 100644 --- a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/TomcatIntegrationTest.java +++ b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/TomcatIntegrationTest.java @@ -36,7 +36,6 @@ void testCollectedMetrics(String dockerImageName, String sampleWebApplicationUrl jvmArgs.add(javaAgentJvmArgument()); jvmArgs.addAll(javaPropertiesToJvmArgs(otelConfigProperties(yamlFiles))); - // testing with a basic tomcat image as test application to capture JVM metrics GenericContainer target = new GenericContainer<>(dockerImageName) .withEnv("CATALINA_OPTS", String.join(" ", jvmArgs)) From 380272ee0ff751da6283a1a4dbbad7945cb4cf64 Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Tue, 17 Jun 2025 14:20:19 +0200 Subject: [PATCH 03/15] add jetty thread metrics --- instrumentation/jmx-metrics/library/jetty.md | 19 ++---- .../src/main/resources/jmx/rules/jetty.yaml | 66 ++++++------------- .../jmx/rules/JettyIntegrationTest.java | 45 +++++++++---- 3 files changed, 57 insertions(+), 73 deletions(-) diff --git a/instrumentation/jmx-metrics/library/jetty.md b/instrumentation/jmx-metrics/library/jetty.md index d771214cfc48..3ddf5926fb3a 100644 --- a/instrumentation/jmx-metrics/library/jetty.md +++ b/instrumentation/jmx-metrics/library/jetty.md @@ -2,15 +2,10 @@ Here is the list of metrics based on MBeans exposed by Jetty. -| Metric Name | Type | Attributes | Description | -| ------------------------------ | ------------- | ------------ | ---------------------------------------------------- | -| jetty.session.sessionsCreated | Counter | resource | The number of sessions established in total | -| jetty.session.sessionTimeTotal | Counter | resource | The total time sessions have been active | -| jetty.session.sessionTimeMax | Gauge | resource | The maximum amount of time a session has been active | -| jetty.session.sessionTimeMean | Gauge | resource | The mean time sessions remain active | -| jetty.threads.busyThreads | UpDownCounter | | The current number of busy threads | -| jetty.threads.idleThreads | UpDownCounter | | The current number of idle threads | -| jetty.threads.maxThreads | UpDownCounter | | The maximum number of threads in the pool | -| jetty.threads.queueSize | UpDownCounter | | The current number of threads in the queue | -| jetty.io.selectCount | Counter | resource, id | The number of select calls | -| jetty.logging.LoggerCount | UpDownCounter | | The number of registered loggers by name | +| Metric Name | Type | Attributes | Description | +|-------------------------|---------------|------------|-------------------------------------------| +| jetty.thread.count | UpDownCounter | | The current number of threads | +| jetty.thread.limit | UpDownCounter | | The maximum number of threads in the pool | +| jetty.thread.busy.count | UpDownCounter | | The current number of busy threads | +| jetty.thread.idle.count | UpDownCounter | | The current number of idle threads | +| jetty.thread.queue.size | UpDownCounter | | The current job queue size | diff --git a/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml b/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml index ed5435d9cc20..f385937243af 100644 --- a/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml +++ b/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml @@ -1,55 +1,27 @@ --- rules: - - bean: org.eclipse.jetty.server.session:context=*,type=sessionhandler,id=* - unit: s - prefix: jetty.session. - type: updowncounter - metricAttribute: - resource: param(context) - mapping: - sessionsCreated: - unit: "{sessions}" - type: counter - desc: The number of sessions established in total - sessionTimeTotal: - type: counter - desc: The total time sessions have been active - sessionTimeMax: - type: gauge - desc: The maximum amount of time a session has been active - sessionTimeMean: - type: gauge - desc: The mean time sessions remain active - - bean: org.eclipse.jetty.util.thread:type=queuedthreadpool,id=* - prefix: jetty.threads. - unit: "{threads}" + prefix: jetty.thread. + unit: "{thread}" type: updowncounter mapping: - busyThreads: - desc: The current number of busy threads + # jetty.thread.count + threads: + metric: count + desc: The current number of threads + # jetty.thread.limit + maxThreads: + metric: limit + desc: The configured maximum number of threads in the pool + # jetty.thread.idle.count idleThreads: + metric: idle.count desc: The current number of idle threads - maxThreads: - desc: The maximum number of threads in the pool + # jetty.thread.busy.count + busyThreads: + metric: busy.count + desc: The current number of busy threads + # jetty.thread.queue.size queueSize: - desc: The current number of threads in the queue - - - bean: org.eclipse.jetty.io:context=*,type=managedselector,id=* - prefix: jetty.io. - metricAttribute: - resource: param(context) - id: param(id) - mapping: - selectCount: - type: counter - unit: "1" - desc: The number of select calls - - - bean: org.eclipse.jetty.logging:type=jettyloggerfactory,id=* - prefix: jetty.logging. - mapping: - LoggerCount: - type: updowncounter - unit: "1" - desc: The number of registered loggers by name + metric: queue.size + desc: The current job queue size diff --git a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java index 03fee02b1e95..2dc17400f664 100644 --- a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java +++ b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java @@ -34,19 +34,20 @@ void testCollectedMetrics() { GenericContainer container = new GenericContainer<>( - new ImageFromDockerfile() - .withDockerfileFromBuilder( - builder -> - builder - .from(DOCKER_IMAGE) - .run( - "java", - "-jar", - "/usr/local/jetty/start.jar", - "--add-to-startd=jmx,stats,http") - .run("mkdir -p /var/lib/jetty/webapps/ROOT/") - .run("touch /var/lib/jetty/webapps/ROOT/index.html") - .build())) + new ImageFromDockerfile() + .withDockerfileFromBuilder( + builder -> + builder + .from(DOCKER_IMAGE) + .run( + "java", + "-jar", + "/usr/local/jetty/start.jar", + // TODO: replace 'stats' with 'statistics' for jetty 12+ + "--add-to-startd=jmx,stats,http") + .run("mkdir -p /var/lib/jetty/webapps/ROOT/") + .run("touch /var/lib/jetty/webapps/ROOT/index.html") + .build())) .withEnv("JAVA_OPTIONS", String.join(" ", jvmArgs)) .withStartupTimeout(Duration.ofMinutes(2)) .withExposedPorts(JETTY_PORT) @@ -60,6 +61,22 @@ void testCollectedMetrics() { } private static MetricsVerifier createMetricsVerifier() { - return MetricsVerifier.create().add("jetty.dummy.metric", metric -> metric.hasDescription("hello")); + return MetricsVerifier.create() + .add("jetty.thread.count", metric -> metric.hasDescription("The current number of threads") + .hasUnit("{thread}").hasDataPointsWithoutAttributes() + .isUpDownCounter()) + .add("jetty.thread.limit", metric -> metric.hasDescription("The configured maximum number of threads in the pool") + .hasUnit("{thread}").hasDataPointsWithoutAttributes() + .isUpDownCounter()) + .add("jetty.thread.idle.count", metric -> metric.hasDescription("The current number of idle threads") + .hasUnit("{thread}").hasDataPointsWithoutAttributes() + .isUpDownCounter()) + .add("jetty.thread.busy.count", metric -> metric.hasDescription("The current number of busy threads") + .hasUnit("{thread}").hasDataPointsWithoutAttributes() + .isUpDownCounter()) + .add("jetty.thread.queue.size", metric -> metric.hasDescription("The current job queue size") + .hasUnit("{thread}").hasDataPointsWithoutAttributes() + .isUpDownCounter()) + ; } } From 7d033ed7d367a796c4acf31166d736e430f3a8fb Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Wed, 18 Jun 2025 10:57:23 +0200 Subject: [PATCH 04/15] try to add jetty 12 --- .../jmx/JmxMetricInsightInstallerTest.java | 6 +- instrumentation/jmx-metrics/library/jetty.md | 15 ++- .../src/main/resources/jmx/rules/jetty.yaml | 19 +++ .../jmx/rules/JettyIntegrationTest.java | 120 ++++++++++++------ 4 files changed, 112 insertions(+), 48 deletions(-) diff --git a/instrumentation/jmx-metrics/javaagent/src/test/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstallerTest.java b/instrumentation/jmx-metrics/javaagent/src/test/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstallerTest.java index baa5fab88abd..c12eb6faec2f 100644 --- a/instrumentation/jmx-metrics/javaagent/src/test/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstallerTest.java +++ b/instrumentation/jmx-metrics/javaagent/src/test/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstallerTest.java @@ -33,11 +33,7 @@ class JmxMetricInsightInstallerTest { private static final Set FILES_TO_BE_TESTED = new HashSet<>( Arrays.asList( - "activemq.yaml", - "camel.yaml", - "hadoop.yaml", - "kafka-broker.yaml", - "wildfly.yaml")); + "activemq.yaml", "camel.yaml", "hadoop.yaml", "kafka-broker.yaml", "wildfly.yaml")); @Test void testToVerifyExistingRulesAreValid() throws Exception { diff --git a/instrumentation/jmx-metrics/library/jetty.md b/instrumentation/jmx-metrics/library/jetty.md index 3ddf5926fb3a..8d16d755c6c7 100644 --- a/instrumentation/jmx-metrics/library/jetty.md +++ b/instrumentation/jmx-metrics/library/jetty.md @@ -2,10 +2,11 @@ Here is the list of metrics based on MBeans exposed by Jetty. -| Metric Name | Type | Attributes | Description | -|-------------------------|---------------|------------|-------------------------------------------| -| jetty.thread.count | UpDownCounter | | The current number of threads | -| jetty.thread.limit | UpDownCounter | | The maximum number of threads in the pool | -| jetty.thread.busy.count | UpDownCounter | | The current number of busy threads | -| jetty.thread.idle.count | UpDownCounter | | The current number of idle threads | -| jetty.thread.queue.size | UpDownCounter | | The current job queue size | +| Metric Name | Type | Attributes | Description | +|-------------------------|---------------|--------------------------------------------|-------------------------------------------| +| jetty.thread.count | UpDownCounter | jetty.thread.pool.id | The current number of threads | +| jetty.thread.limit | UpDownCounter | jetty.thread.pool.id | The maximum number of threads in the pool | +| jetty.thread.busy.count | UpDownCounter | jetty.thread.pool.id | The current number of busy threads | +| jetty.thread.idle.count | UpDownCounter | jetty.thread.pool.id | The current number of idle threads | +| jetty.thread.queue.size | UpDownCounter | jetty.thread.pool.id | The current job queue size | +| jetty.io.select.count | Counter | jetty.selector.resource, jetty.selector.id | The number of select calls | diff --git a/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml b/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml index f385937243af..40d7dc69ecc1 100644 --- a/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml +++ b/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml @@ -1,9 +1,13 @@ --- rules: + - bean: org.eclipse.jetty.util.thread:type=queuedthreadpool,id=* prefix: jetty.thread. unit: "{thread}" type: updowncounter + metricAttribute: + # 'id' is a "technical ID" with a single '0' value by default + jetty.thread.pool.id: param(id) mapping: # jetty.thread.count threads: @@ -25,3 +29,18 @@ rules: queueSize: metric: queue.size desc: The current job queue size + + - bean: org.eclipse.jetty.io:context=*,type=managedselector,id=* + metricAttribute: + # 'id' is a numerical value in [0,9] by default + # 'context' is a high cardinality value like 'HTTP_1_1@7674f035' but likely stable for the + # duration of the jetty process lifecycle + jetty.selector.context: param(context) + jetty.selector.id: param(id) + mapping: + # jetty.select.count + selectCount: + metric: jetty.select.count + type: counter + unit: "{operation}" + desc: The number of select calls diff --git a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java index 2dc17400f664..3dc86e73fa0e 100644 --- a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java +++ b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java @@ -5,24 +5,27 @@ package io.opentelemetry.instrumentation.jmx.rules; +import static io.opentelemetry.instrumentation.jmx.rules.assertions.DataPointAttributes.attributeGroup; +import static io.opentelemetry.instrumentation.jmx.rules.assertions.DataPointAttributes.attributeWithAnyValue; + +import io.opentelemetry.instrumentation.jmx.rules.assertions.AttributeMatcher; import java.time.Duration; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.images.builder.ImageFromDockerfile; public class JettyIntegrationTest extends TargetSystemTest { - // TODO: test with multiple versions - - private static final String DOCKER_IMAGE = "jetty:11"; private static final int JETTY_PORT = 8080; - @Test - void testCollectedMetrics() { + @ParameterizedTest + @ValueSource(ints = {11, 12}) + void testCollectedMetrics(int jettyMajorVersion) { List yamlFiles = Collections.singletonList("jetty.yaml"); @@ -32,22 +35,29 @@ void testCollectedMetrics() { jvmArgs.add(javaAgentJvmArgument()); jvmArgs.addAll(javaPropertiesToJvmArgs(otelConfigProperties(yamlFiles))); + String jettyModules = "jmx,http,"; + if (jettyMajorVersion >= 12) { + jettyModules += "statistics"; + } else { + jettyModules += "stats"; + } + String addModulesArg = "--add-to-startd=" + jettyModules; + GenericContainer container = new GenericContainer<>( - new ImageFromDockerfile() - .withDockerfileFromBuilder( - builder -> - builder - .from(DOCKER_IMAGE) - .run( - "java", - "-jar", - "/usr/local/jetty/start.jar", - // TODO: replace 'stats' with 'statistics' for jetty 12+ - "--add-to-startd=jmx,stats,http") - .run("mkdir -p /var/lib/jetty/webapps/ROOT/") - .run("touch /var/lib/jetty/webapps/ROOT/index.html") - .build())) + new ImageFromDockerfile() + .withDockerfileFromBuilder( + builder -> + builder + .from("jetty:" + jettyMajorVersion) + .run( + "java", + "-jar", + "/usr/local/jetty/start.jar", + addModulesArg) + .run("mkdir -p /var/lib/jetty/webapps/ROOT/") + .run("touch /var/lib/jetty/webapps/ROOT/index.html") + .build())) .withEnv("JAVA_OPTIONS", String.join(" ", jvmArgs)) .withStartupTimeout(Duration.ofMinutes(2)) .withExposedPorts(JETTY_PORT) @@ -61,22 +71,60 @@ void testCollectedMetrics() { } private static MetricsVerifier createMetricsVerifier() { + + AttributeMatcher threadPoolId = attributeWithAnyValue("jetty.thread.pool.id"); + return MetricsVerifier.create() - .add("jetty.thread.count", metric -> metric.hasDescription("The current number of threads") - .hasUnit("{thread}").hasDataPointsWithoutAttributes() - .isUpDownCounter()) - .add("jetty.thread.limit", metric -> metric.hasDescription("The configured maximum number of threads in the pool") - .hasUnit("{thread}").hasDataPointsWithoutAttributes() - .isUpDownCounter()) - .add("jetty.thread.idle.count", metric -> metric.hasDescription("The current number of idle threads") - .hasUnit("{thread}").hasDataPointsWithoutAttributes() - .isUpDownCounter()) - .add("jetty.thread.busy.count", metric -> metric.hasDescription("The current number of busy threads") - .hasUnit("{thread}").hasDataPointsWithoutAttributes() - .isUpDownCounter()) - .add("jetty.thread.queue.size", metric -> metric.hasDescription("The current job queue size") - .hasUnit("{thread}").hasDataPointsWithoutAttributes() - .isUpDownCounter()) - ; + .add( + "jetty.thread.count", + metric -> + metric + .hasDescription("The current number of threads") + .hasUnit("{thread}") + .hasDataPointsWithOneAttribute(threadPoolId) + .isUpDownCounter()) + .add( + "jetty.thread.limit", + metric -> + metric + .hasDescription("The configured maximum number of threads in the pool") + .hasUnit("{thread}") + .hasDataPointsWithOneAttribute(threadPoolId) + .isUpDownCounter()) + .add( + "jetty.thread.idle.count", + metric -> + metric + .hasDescription("The current number of idle threads") + .hasUnit("{thread}") + .hasDataPointsWithOneAttribute(threadPoolId) + .isUpDownCounter()) + .add( + "jetty.thread.busy.count", + metric -> + metric + .hasDescription("The current number of busy threads") + .hasUnit("{thread}") + .hasDataPointsWithOneAttribute(threadPoolId) + .isUpDownCounter()) + .add( + "jetty.thread.queue.size", + metric -> + metric + .hasDescription("The current job queue size") + .hasUnit("{thread}") + .hasDataPointsWithOneAttribute(threadPoolId) + .isUpDownCounter()) + .add( + "jetty.select.count", + metric -> + metric + .hasDescription("The number of select calls") + .hasUnit("{operation}") + .hasDataPointsWithAttributes( + attributeGroup( + attributeWithAnyValue("jetty.selector.id"), + attributeWithAnyValue("jetty.selector.context"))) + .isCounter()); } } From 48d37a974cb64cc3c8a93d7bea1840025e7eae79 Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Wed, 18 Jun 2025 11:09:59 +0200 Subject: [PATCH 05/15] limit test to jetty 11 --- .../instrumentation/jmx/rules/JettyIntegrationTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java index 3dc86e73fa0e..0bdec8a916eb 100644 --- a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java +++ b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java @@ -24,7 +24,7 @@ public class JettyIntegrationTest extends TargetSystemTest { private static final int JETTY_PORT = 8080; @ParameterizedTest - @ValueSource(ints = {11, 12}) + @ValueSource(ints = {11}) // TODO: add support for Jetty 12 void testCollectedMetrics(int jettyMajorVersion) { List yamlFiles = Collections.singletonList("jetty.yaml"); From a08ce7809ed236a27dd101161f08ab101d35bf6a Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Wed, 18 Jun 2025 18:28:30 +0200 Subject: [PATCH 06/15] test multiple jetty versions + doc --- instrumentation/jmx-metrics/library/jetty.md | 23 +++++++++++- .../src/main/resources/jmx/rules/jetty.yaml | 36 ++++++++++++++++++- .../jmx/rules/JettyIntegrationTest.java | 34 ++++++++++-------- 3 files changed, 76 insertions(+), 17 deletions(-) diff --git a/instrumentation/jmx-metrics/library/jetty.md b/instrumentation/jmx-metrics/library/jetty.md index 8d16d755c6c7..87329f72841a 100644 --- a/instrumentation/jmx-metrics/library/jetty.md +++ b/instrumentation/jmx-metrics/library/jetty.md @@ -1,6 +1,27 @@ # Jetty Metrics -Here is the list of metrics based on MBeans exposed by Jetty. +Here is the list of metrics based on MBeans exposed by [Jetty](https://jetty.org/). + +The metrics captured and their respective attributes depend on the Jetty version: +- [Jetty 12 and later](#jetty-12-and-later) +- [Jetty 11 and earlier](#jetty-9-to-11) + +## Jetty 12 and later + +Those metrics require the following Jetty modules to be enabled : `jmx`, `http` and `statistics`. + +| Metric Name | Type | Attributes | Description | +|-------------------------|---------------|--------------------------------------------|-------------------------------------------| +| jetty.thread.count | UpDownCounter | jetty.thread.pool.id, jetty.thread.context | The current number of threads | +| jetty.thread.limit | UpDownCounter | jetty.thread.pool.id, jetty.thread.context | The maximum number of threads in the pool | +| jetty.thread.busy.count | UpDownCounter | jetty.thread.pool.id, jetty.thread.context | The current number of busy threads | +| jetty.thread.idle.count | UpDownCounter | jetty.thread.pool.id, jetty.thread.context | The current number of idle threads | +| jetty.thread.queue.size | UpDownCounter | jetty.thread.pool.id, jetty.thread.context | The current job queue size | +| jetty.io.select.count | Counter | jetty.selector.resource, jetty.selector.id | The number of select calls | + +## Jetty 9 to 11 + +Those metrics require the following Jetty modules to be enabled : `jmx`, `http` and `stats`. | Metric Name | Type | Attributes | Description | |-------------------------|---------------|--------------------------------------------|-------------------------------------------| diff --git a/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml b/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml index 40d7dc69ecc1..2ba8a29edcde 100644 --- a/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml +++ b/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml @@ -1,6 +1,40 @@ --- rules: + # Thread metrics for Jetty 12 and later + - bean: org.eclipse.jetty.util.thread:context=*,type=queuedthreadpool,id=* + prefix: jetty.thread. + unit: "{thread}" + type: updowncounter + metricAttribute: + # 'id' is a "technical ID" with a single '0' value by default + jetty.thread.pool.id: param(id) + # 'context' is a high cardinality value like 'Server@5a411614' but likely stable for the + # duration of the jetty process lifecycle + jetty.thread.context: param(context) + mapping: + # jetty.thread.count + threads: + metric: count + desc: The current number of threads + # jetty.thread.limit + maxThreads: + metric: limit + desc: The configured maximum number of threads in the pool + # jetty.thread.idle.count + idleThreads: + metric: idle.count + desc: The current number of idle threads + # jetty.thread.busy.count + busyThreads: + metric: busy.count + desc: The current number of busy threads + # jetty.thread.queue.size + queueSize: + metric: queue.size + desc: The current job queue size + + # Thread metrics for Jetty 11 and earlier - bean: org.eclipse.jetty.util.thread:type=queuedthreadpool,id=* prefix: jetty.thread. unit: "{thread}" @@ -33,9 +67,9 @@ rules: - bean: org.eclipse.jetty.io:context=*,type=managedselector,id=* metricAttribute: # 'id' is a numerical value in [0,9] by default + jetty.selector.context: param(context) # 'context' is a high cardinality value like 'HTTP_1_1@7674f035' but likely stable for the # duration of the jetty process lifecycle - jetty.selector.context: param(context) jetty.selector.id: param(id) mapping: # jetty.select.count diff --git a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java index 0bdec8a916eb..c852b9dfe268 100644 --- a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java +++ b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java @@ -8,7 +8,7 @@ import static io.opentelemetry.instrumentation.jmx.rules.assertions.DataPointAttributes.attributeGroup; import static io.opentelemetry.instrumentation.jmx.rules.assertions.DataPointAttributes.attributeWithAnyValue; -import io.opentelemetry.instrumentation.jmx.rules.assertions.AttributeMatcher; +import io.opentelemetry.instrumentation.jmx.rules.assertions.AttributeMatcherGroup; import java.time.Duration; import java.util.ArrayList; import java.util.Collections; @@ -24,7 +24,7 @@ public class JettyIntegrationTest extends TargetSystemTest { private static final int JETTY_PORT = 8080; @ParameterizedTest - @ValueSource(ints = {11}) // TODO: add support for Jetty 12 + @ValueSource(ints = {9, 10, 11, 12}) void testCollectedMetrics(int jettyMajorVersion) { List yamlFiles = Collections.singletonList("jetty.yaml"); @@ -50,11 +50,7 @@ void testCollectedMetrics(int jettyMajorVersion) { builder -> builder .from("jetty:" + jettyMajorVersion) - .run( - "java", - "-jar", - "/usr/local/jetty/start.jar", - addModulesArg) + .run("java", "-jar", "/usr/local/jetty/start.jar", addModulesArg) .run("mkdir -p /var/lib/jetty/webapps/ROOT/") .run("touch /var/lib/jetty/webapps/ROOT/index.html") .build())) @@ -67,12 +63,20 @@ void testCollectedMetrics(int jettyMajorVersion) { startTarget(container); - verifyMetrics(createMetricsVerifier()); + verifyMetrics(createMetricsVerifier(jettyMajorVersion)); } - private static MetricsVerifier createMetricsVerifier() { + private static MetricsVerifier createMetricsVerifier(int jettyMajorVersion) { - AttributeMatcher threadPoolId = attributeWithAnyValue("jetty.thread.pool.id"); + AttributeMatcherGroup threadPoolAttributes; + if (jettyMajorVersion >= 12) { + threadPoolAttributes = + attributeGroup( + attributeWithAnyValue("jetty.thread.pool.id"), + attributeWithAnyValue("jetty.thread.context")); + } else { + threadPoolAttributes = attributeGroup(attributeWithAnyValue("jetty.thread.pool.id")); + } return MetricsVerifier.create() .add( @@ -81,7 +85,7 @@ private static MetricsVerifier createMetricsVerifier() { metric .hasDescription("The current number of threads") .hasUnit("{thread}") - .hasDataPointsWithOneAttribute(threadPoolId) + .hasDataPointsWithAttributes(threadPoolAttributes) .isUpDownCounter()) .add( "jetty.thread.limit", @@ -89,7 +93,7 @@ private static MetricsVerifier createMetricsVerifier() { metric .hasDescription("The configured maximum number of threads in the pool") .hasUnit("{thread}") - .hasDataPointsWithOneAttribute(threadPoolId) + .hasDataPointsWithAttributes(threadPoolAttributes) .isUpDownCounter()) .add( "jetty.thread.idle.count", @@ -97,7 +101,7 @@ private static MetricsVerifier createMetricsVerifier() { metric .hasDescription("The current number of idle threads") .hasUnit("{thread}") - .hasDataPointsWithOneAttribute(threadPoolId) + .hasDataPointsWithAttributes(threadPoolAttributes) .isUpDownCounter()) .add( "jetty.thread.busy.count", @@ -105,7 +109,7 @@ private static MetricsVerifier createMetricsVerifier() { metric .hasDescription("The current number of busy threads") .hasUnit("{thread}") - .hasDataPointsWithOneAttribute(threadPoolId) + .hasDataPointsWithAttributes(threadPoolAttributes) .isUpDownCounter()) .add( "jetty.thread.queue.size", @@ -113,7 +117,7 @@ private static MetricsVerifier createMetricsVerifier() { metric .hasDescription("The current job queue size") .hasUnit("{thread}") - .hasDataPointsWithOneAttribute(threadPoolId) + .hasDataPointsWithAttributes(threadPoolAttributes) .isUpDownCounter()) .add( "jetty.select.count", From ec7946cdc7989d8c692a8314a6e8a5d46224d991 Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Wed, 18 Jun 2025 18:29:03 +0200 Subject: [PATCH 07/15] fix link text --- instrumentation/jmx-metrics/library/jetty.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/jmx-metrics/library/jetty.md b/instrumentation/jmx-metrics/library/jetty.md index 87329f72841a..a2fb7452c3cc 100644 --- a/instrumentation/jmx-metrics/library/jetty.md +++ b/instrumentation/jmx-metrics/library/jetty.md @@ -4,7 +4,7 @@ Here is the list of metrics based on MBeans exposed by [Jetty](https://jetty.org The metrics captured and their respective attributes depend on the Jetty version: - [Jetty 12 and later](#jetty-12-and-later) -- [Jetty 11 and earlier](#jetty-9-to-11) +- [Jetty 9 to 11](#jetty-9-to-11) ## Jetty 12 and later From 7ccf85218e881814a714fcdcc9fc6b240aedf08d Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Wed, 18 Jun 2025 18:32:50 +0200 Subject: [PATCH 08/15] use docket image name as test param --- .../instrumentation/jmx/rules/JettyIntegrationTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java index c852b9dfe268..eb715adc75f8 100644 --- a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java +++ b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java @@ -23,7 +23,7 @@ public class JettyIntegrationTest extends TargetSystemTest { private static final int JETTY_PORT = 8080; - @ParameterizedTest + @ParameterizedTest(name="jetty:{arguments}") @ValueSource(ints = {9, 10, 11, 12}) void testCollectedMetrics(int jettyMajorVersion) { From 1027242502138f0d120edfe7bbcb6df3ea3a32d9 Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Wed, 18 Jun 2025 21:37:40 +0200 Subject: [PATCH 09/15] test for session metrics for jetty < 12 --- .../src/main/resources/jmx/rules/jetty.yaml | 33 ++++ .../jmx/rules/JettyIntegrationTest.java | 157 ++++++++++++------ 2 files changed, 137 insertions(+), 53 deletions(-) diff --git a/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml b/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml index 2ba8a29edcde..c60d004be0c0 100644 --- a/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml +++ b/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml @@ -78,3 +78,36 @@ rules: type: counter unit: "{operation}" desc: The number of select calls + + - bean: org.eclipse.jetty.server.session:context=*,type=sessionhandler,id=* + prefix: jetty.session. + metricAttribute: + jetty.context: param(context) + jetty.session.handler.id: param(id) + mapping: + # jetty.session.created.count + sessionsCreated: + metric: created.count + unit: "{session}" + type: counter + desc: The total number of created sessions + # jetty.session.duration.sum + sessionTimeTotal: + metric: duration.sum + unit: s + type: counter + desc: The cumulated session duration + # jetty.session.duration.max + sessionTimeMax: + metric: duration.max + unit: s + # gauge because it can't be aggregated + type: gauge + desc: The maximum session duration + # jetty.session.duration.mean + sessionTimeMean: + metric: duration.mean + unit: s + # gauge because it can't be aggregated + type: gauge + desc: The mean session duration diff --git a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java index eb715adc75f8..ca3b27735213 100644 --- a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java +++ b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java @@ -23,7 +23,7 @@ public class JettyIntegrationTest extends TargetSystemTest { private static final int JETTY_PORT = 8080; - @ParameterizedTest(name="jetty:{arguments}") + @ParameterizedTest(name = "jetty:{arguments}") @ValueSource(ints = {9, 10, 11, 12}) void testCollectedMetrics(int jettyMajorVersion) { @@ -78,57 +78,108 @@ private static MetricsVerifier createMetricsVerifier(int jettyMajorVersion) { threadPoolAttributes = attributeGroup(attributeWithAnyValue("jetty.thread.pool.id")); } - return MetricsVerifier.create() - .add( - "jetty.thread.count", - metric -> - metric - .hasDescription("The current number of threads") - .hasUnit("{thread}") - .hasDataPointsWithAttributes(threadPoolAttributes) - .isUpDownCounter()) - .add( - "jetty.thread.limit", - metric -> - metric - .hasDescription("The configured maximum number of threads in the pool") - .hasUnit("{thread}") - .hasDataPointsWithAttributes(threadPoolAttributes) - .isUpDownCounter()) - .add( - "jetty.thread.idle.count", - metric -> - metric - .hasDescription("The current number of idle threads") - .hasUnit("{thread}") - .hasDataPointsWithAttributes(threadPoolAttributes) - .isUpDownCounter()) - .add( - "jetty.thread.busy.count", - metric -> - metric - .hasDescription("The current number of busy threads") - .hasUnit("{thread}") - .hasDataPointsWithAttributes(threadPoolAttributes) - .isUpDownCounter()) - .add( - "jetty.thread.queue.size", - metric -> - metric - .hasDescription("The current job queue size") - .hasUnit("{thread}") - .hasDataPointsWithAttributes(threadPoolAttributes) - .isUpDownCounter()) - .add( - "jetty.select.count", - metric -> - metric - .hasDescription("The number of select calls") - .hasUnit("{operation}") - .hasDataPointsWithAttributes( - attributeGroup( - attributeWithAnyValue("jetty.selector.id"), - attributeWithAnyValue("jetty.selector.context"))) - .isCounter()); + MetricsVerifier verifier = + MetricsVerifier.create() + .add( + "jetty.thread.count", + metric -> + metric + .isUpDownCounter() + .hasDescription("The current number of threads") + .hasUnit("{thread}") + .hasDataPointsWithAttributes(threadPoolAttributes)) + .add( + "jetty.thread.limit", + metric -> + metric + .isUpDownCounter() + .hasDescription("The configured maximum number of threads in the pool") + .hasUnit("{thread}") + .hasDataPointsWithAttributes(threadPoolAttributes)) + .add( + "jetty.thread.idle.count", + metric -> + metric + .isUpDownCounter() + .hasDescription("The current number of idle threads") + .hasUnit("{thread}") + .hasDataPointsWithAttributes(threadPoolAttributes)) + .add( + "jetty.thread.busy.count", + metric -> + metric + .isUpDownCounter() + .hasDescription("The current number of busy threads") + .hasUnit("{thread}") + .hasDataPointsWithAttributes(threadPoolAttributes)) + .add( + "jetty.thread.queue.size", + metric -> + metric + .isUpDownCounter() + .hasDescription("The current job queue size") + .hasUnit("{thread}") + .hasDataPointsWithAttributes(threadPoolAttributes)) + .add( + "jetty.select.count", + metric -> + metric + .isCounter() + .hasDescription("The number of select calls") + .hasUnit("{operation}") + .hasDataPointsWithAttributes( + attributeGroup( + attributeWithAnyValue("jetty.selector.id"), + attributeWithAnyValue("jetty.selector.context")))); + + if (jettyMajorVersion < 12) { + verifier + .add( + "jetty.session.created.count", + metric -> + metric + .isCounter() + .hasDescription("The total number of created sessions") + .hasUnit("{session}") + .hasDataPointsWithAttributes( + attributeGroup( + attributeWithAnyValue("jetty.context"), + attributeWithAnyValue("jetty.session.handler.id")))) + .add( + "jetty.session.duration.sum", + metric -> + metric + .isCounter() + .hasDescription("The cumulated session duration") + .hasUnit("s") + .hasDataPointsWithAttributes( + attributeGroup( + attributeWithAnyValue("jetty.context"), + attributeWithAnyValue("jetty.session.handler.id")))) + .add( + "jetty.session.duration.max", + metric -> + metric + .isGauge() + .hasDescription("The maximum session duration") + .hasUnit("s") + .hasDataPointsWithAttributes( + attributeGroup( + attributeWithAnyValue("jetty.context"), + attributeWithAnyValue("jetty.session.handler.id")))) + .add( + "jetty.session.duration.mean", + metric -> + metric + .isGauge() + .hasDescription("The mean session duration") + .hasUnit("s") + .hasDataPointsWithAttributes( + attributeGroup( + attributeWithAnyValue("jetty.context"), + attributeWithAnyValue("jetty.session.handler.id")))); + } + + return verifier; } } From a8793e37af3c80c8253cae5e846aaf6d07bda89d Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Wed, 18 Jun 2025 22:21:16 +0200 Subject: [PATCH 10/15] try to add jetty 12 session metrics (failing) --- .../src/main/resources/jmx/rules/jetty.yaml | 28 +++++++++++++- .../jmx/rules/JettyIntegrationTest.java | 38 ++++++++++++++++--- 2 files changed, 59 insertions(+), 7 deletions(-) diff --git a/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml b/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml index c60d004be0c0..665beb0a565a 100644 --- a/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml +++ b/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml @@ -34,7 +34,7 @@ rules: metric: queue.size desc: The current job queue size - # Thread metrics for Jetty 11 and earlier + # Thread metrics for Jetty 9 to 11 - bean: org.eclipse.jetty.util.thread:type=queuedthreadpool,id=* prefix: jetty.thread. unit: "{thread}" @@ -79,10 +79,36 @@ rules: unit: "{operation}" desc: The number of select calls + # Session metrics for Jetty 12 + - bean: org.eclipse.jetty.session:context=*,type=defaultsessioncache,id=* + # org.eclipse.jetty.session:context=ROOT,type=defaultsessioncache,id=0 + prefix: jetty.session. + unit: "{session}" + metricAttribute: + # 'context' corresponds to the webapp context path + jetty.context: param(context) + # 'id' is a "technical ID" with a single '0' value by default + jetty.session.cache.id: param(id) + mapping: + # jetty.session.count + sessionsCurrent: + metric: count + type: updowncounter + desc: Current number of active sessions + # jetty.session.count.max + sessionsMax: + metric: count.max + # gauge because it can't be aggregated + type: gauge + desc: Maximum number of active sessions + + # Session metrics for Jetty 9 to 11 - bean: org.eclipse.jetty.server.session:context=*,type=sessionhandler,id=* prefix: jetty.session. metricAttribute: + # 'context' corresponds to the webapp context path jetty.context: param(context) + # 'id' is a "technical ID" with a single '0' value by default jetty.session.handler.id: param(id) mapping: # jetty.session.created.count diff --git a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java index ca3b27735213..ba55bba85471 100644 --- a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java +++ b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java @@ -11,8 +11,11 @@ import io.opentelemetry.instrumentation.jmx.rules.assertions.AttributeMatcherGroup; import java.time.Duration; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import org.testcontainers.containers.GenericContainer; @@ -35,13 +38,13 @@ void testCollectedMetrics(int jettyMajorVersion) { jvmArgs.add(javaAgentJvmArgument()); jvmArgs.addAll(javaPropertiesToJvmArgs(otelConfigProperties(yamlFiles))); - String jettyModules = "jmx,http,"; + Set jettyModules = new HashSet<>(Arrays.asList("jmx", "http")); if (jettyMajorVersion >= 12) { - jettyModules += "statistics"; + jettyModules.add("statistics"); } else { - jettyModules += "stats"; + jettyModules.add("stats"); } - String addModulesArg = "--add-to-startd=" + jettyModules; + String addModulesArg = "--add-to-startd=" + String.join(",", jettyModules); GenericContainer container = new GenericContainer<>( @@ -132,7 +135,31 @@ private static MetricsVerifier createMetricsVerifier(int jettyMajorVersion) { attributeWithAnyValue("jetty.selector.id"), attributeWithAnyValue("jetty.selector.context")))); - if (jettyMajorVersion < 12) { + if (jettyMajorVersion >= 12) { + verifier + .add( + "jetty.session.count", + metric -> + metric + .isUpDownCounter() + .hasDescription("Current number of active sessions") + .hasUnit("{session}") + .hasDataPointsWithAttributes( + attributeGroup( + attributeWithAnyValue("jetty.context"), + attributeWithAnyValue("jetty.session.cache.id")))) + .add( + "jetty.session.count.max", + metric -> + metric + .isUpDownCounter() + .hasDescription("Maximum number of active sessions") + .hasUnit("{session}") + .hasDataPointsWithAttributes( + attributeGroup( + attributeWithAnyValue("jetty.context"), + attributeWithAnyValue("jetty.session.cache.id")))); + } else { verifier .add( "jetty.session.created.count", @@ -179,7 +206,6 @@ private static MetricsVerifier createMetricsVerifier(int jettyMajorVersion) { attributeWithAnyValue("jetty.context"), attributeWithAnyValue("jetty.session.handler.id")))); } - return verifier; } } From 327b2e7bf1d45ed410c1151b502942c2f3310488 Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Thu, 19 Jun 2025 11:34:35 +0200 Subject: [PATCH 11/15] finish jetty 12 support + doc --- instrumentation/jmx-metrics/library/jetty.md | 40 ++++++++++++++----- .../src/main/resources/jmx/rules/jetty.yaml | 5 +-- .../jmx/rules/JettyIntegrationTest.java | 7 +++- 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/instrumentation/jmx-metrics/library/jetty.md b/instrumentation/jmx-metrics/library/jetty.md index a2fb7452c3cc..5f503da77560 100644 --- a/instrumentation/jmx-metrics/library/jetty.md +++ b/instrumentation/jmx-metrics/library/jetty.md @@ -8,7 +8,7 @@ The metrics captured and their respective attributes depend on the Jetty version ## Jetty 12 and later -Those metrics require the following Jetty modules to be enabled : `jmx`, `http` and `statistics`. +Those metrics require the following Jetty modules to be enabled : `jmx`, `http`, `statistics`, `sessions` and at least one of `ee8-deploy`, `ee9-deploy` or `ee10-deploy`. | Metric Name | Type | Attributes | Description | |-------------------------|---------------|--------------------------------------------|-------------------------------------------| @@ -17,17 +17,37 @@ Those metrics require the following Jetty modules to be enabled : `jmx`, `http` | jetty.thread.busy.count | UpDownCounter | jetty.thread.pool.id, jetty.thread.context | The current number of busy threads | | jetty.thread.idle.count | UpDownCounter | jetty.thread.pool.id, jetty.thread.context | The current number of idle threads | | jetty.thread.queue.size | UpDownCounter | jetty.thread.pool.id, jetty.thread.context | The current job queue size | -| jetty.io.select.count | Counter | jetty.selector.resource, jetty.selector.id | The number of select calls | +| jetty.io.select.count | Counter | jetty.selector.context, jetty.selector.id | The number of select calls | +| jetty.session.count | UpDownCounter | jetty.context, jetty.session.cache.id | Current number of active sessions | +| jetty.session.count.max | Gauge | jetty.context, jetty.session.cache.id | Maximum number of active sessions | + +- `jetty.context` corresponds to the deployed application subfolder in `webapps` folder. +- `jetty.selector.context` is a technical string identifier, high cardinality with values like `HTTP_1_1@7674f035` but stable per Jetty process instance +- `jetty.selector.id` is a technical numeric identifier, usually with low cardinality between `0` and `9`. +- `jetty.session.cache.id` is a technical numeric identifier, usually single `0` value is used +- `jetty.thread.context` is a technical string identifier, high cardinality with values like `Server@5a411614` but stable per Jetty process instance +- `jetty.thread.pool.id` is a technical numeric identifier, usually single `0` value is used ## Jetty 9 to 11 Those metrics require the following Jetty modules to be enabled : `jmx`, `http` and `stats`. -| Metric Name | Type | Attributes | Description | -|-------------------------|---------------|--------------------------------------------|-------------------------------------------| -| jetty.thread.count | UpDownCounter | jetty.thread.pool.id | The current number of threads | -| jetty.thread.limit | UpDownCounter | jetty.thread.pool.id | The maximum number of threads in the pool | -| jetty.thread.busy.count | UpDownCounter | jetty.thread.pool.id | The current number of busy threads | -| jetty.thread.idle.count | UpDownCounter | jetty.thread.pool.id | The current number of idle threads | -| jetty.thread.queue.size | UpDownCounter | jetty.thread.pool.id | The current job queue size | -| jetty.io.select.count | Counter | jetty.selector.resource, jetty.selector.id | The number of select calls | +| Metric Name | Type | Attributes | Description | +|-----------------------------|---------------|-------------------------------------------|-------------------------------------------| +| jetty.thread.count | UpDownCounter | jetty.thread.pool.id | The current number of threads | +| jetty.thread.limit | UpDownCounter | jetty.thread.pool.id | The maximum number of threads in the pool | +| jetty.thread.busy.count | UpDownCounter | jetty.thread.pool.id | The current number of busy threads | +| jetty.thread.idle.count | UpDownCounter | jetty.thread.pool.id | The current number of idle threads | +| jetty.thread.queue.size | UpDownCounter | jetty.thread.pool.id | The current job queue size | +| jetty.io.select.count | Counter | jetty.selector.context, jetty.selector.id | The number of select calls | +| jetty.session.created.count | Counter | jetty.context, jetty.session.handler.id | The total number of created sessions | +| jetty.session.duration.sum | Gauge | jetty.context, jetty.session.handler.id | The cumulated session duration | +| jetty.session.duration.max | Gauge | jetty.context, jetty.session.handler.id | The maximum session duration | +| jetty.session.duration.mean | Gauge | jetty.context, jetty.session.handler.id | The mean session duration | + +- `jetty.context` corresponds to the deployed application subfolder in `webapps` folder. +- `jetty.selector.context` is a technical string identifier, high cardinality with values like `HTTP_1_1@7674f035` but stable per Jetty process instance +- `jetty.selector.id` is a technical numeric identifier, usually with low cardinality between `0` and `9`. +- `jetty.session.cache.id` is a technical numeric identifier, usually single `0` value is used +- `jetty.thread.pool.id` is a technical numeric identifier, usually single `0` value is used +- `jetty.session.handler.id` is a technical numeric identifier, usually single `0` value is used diff --git a/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml b/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml index 665beb0a565a..846e4cf6000e 100644 --- a/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml +++ b/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml @@ -66,10 +66,10 @@ rules: - bean: org.eclipse.jetty.io:context=*,type=managedselector,id=* metricAttribute: - # 'id' is a numerical value in [0,9] by default - jetty.selector.context: param(context) # 'context' is a high cardinality value like 'HTTP_1_1@7674f035' but likely stable for the # duration of the jetty process lifecycle + jetty.selector.context: param(context) + # 'id' is a numerical value in [0,9] by default jetty.selector.id: param(id) mapping: # jetty.select.count @@ -81,7 +81,6 @@ rules: # Session metrics for Jetty 12 - bean: org.eclipse.jetty.session:context=*,type=defaultsessioncache,id=* - # org.eclipse.jetty.session:context=ROOT,type=defaultsessioncache,id=0 prefix: jetty.session. unit: "{session}" metricAttribute: diff --git a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java index ba55bba85471..374360a63d55 100644 --- a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java +++ b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java @@ -41,7 +41,12 @@ void testCollectedMetrics(int jettyMajorVersion) { Set jettyModules = new HashSet<>(Arrays.asList("jmx", "http")); if (jettyMajorVersion >= 12) { jettyModules.add("statistics"); + // required for session management + jettyModules.add("sessions"); + // required for deployment support in 'webapps' folder + jettyModules.add("ee10-deploy"); } else { + // with older versions deployment and session management are available by default jettyModules.add("stats"); } String addModulesArg = "--add-to-startd=" + String.join(",", jettyModules); @@ -152,7 +157,7 @@ private static MetricsVerifier createMetricsVerifier(int jettyMajorVersion) { "jetty.session.count.max", metric -> metric - .isUpDownCounter() + .isGauge() .hasDescription("Maximum number of active sessions") .hasUnit("{session}") .hasDataPointsWithAttributes( From 141263bb19e27fae4693b9f1ca816fdee80bb3d3 Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Mon, 23 Jun 2025 18:28:09 +0200 Subject: [PATCH 12/15] remove useless attributes --- .../jmx/rules/JettyIntegrationTest.java | 59 +++++-------------- 1 file changed, 14 insertions(+), 45 deletions(-) diff --git a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java index 374360a63d55..2397977aa9c7 100644 --- a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java +++ b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java @@ -5,10 +5,9 @@ package io.opentelemetry.instrumentation.jmx.rules; -import static io.opentelemetry.instrumentation.jmx.rules.assertions.DataPointAttributes.attributeGroup; import static io.opentelemetry.instrumentation.jmx.rules.assertions.DataPointAttributes.attributeWithAnyValue; -import io.opentelemetry.instrumentation.jmx.rules.assertions.AttributeMatcherGroup; +import io.opentelemetry.instrumentation.jmx.rules.assertions.AttributeMatcher; import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; @@ -76,16 +75,6 @@ void testCollectedMetrics(int jettyMajorVersion) { private static MetricsVerifier createMetricsVerifier(int jettyMajorVersion) { - AttributeMatcherGroup threadPoolAttributes; - if (jettyMajorVersion >= 12) { - threadPoolAttributes = - attributeGroup( - attributeWithAnyValue("jetty.thread.pool.id"), - attributeWithAnyValue("jetty.thread.context")); - } else { - threadPoolAttributes = attributeGroup(attributeWithAnyValue("jetty.thread.pool.id")); - } - MetricsVerifier verifier = MetricsVerifier.create() .add( @@ -95,7 +84,7 @@ private static MetricsVerifier createMetricsVerifier(int jettyMajorVersion) { .isUpDownCounter() .hasDescription("The current number of threads") .hasUnit("{thread}") - .hasDataPointsWithAttributes(threadPoolAttributes)) + .hasDataPointsWithoutAttributes()) .add( "jetty.thread.limit", metric -> @@ -103,7 +92,7 @@ private static MetricsVerifier createMetricsVerifier(int jettyMajorVersion) { .isUpDownCounter() .hasDescription("The configured maximum number of threads in the pool") .hasUnit("{thread}") - .hasDataPointsWithAttributes(threadPoolAttributes)) + .hasDataPointsWithoutAttributes()) .add( "jetty.thread.idle.count", metric -> @@ -111,7 +100,7 @@ private static MetricsVerifier createMetricsVerifier(int jettyMajorVersion) { .isUpDownCounter() .hasDescription("The current number of idle threads") .hasUnit("{thread}") - .hasDataPointsWithAttributes(threadPoolAttributes)) + .hasDataPointsWithoutAttributes()) .add( "jetty.thread.busy.count", metric -> @@ -119,7 +108,7 @@ private static MetricsVerifier createMetricsVerifier(int jettyMajorVersion) { .isUpDownCounter() .hasDescription("The current number of busy threads") .hasUnit("{thread}") - .hasDataPointsWithAttributes(threadPoolAttributes)) + .hasDataPointsWithoutAttributes()) .add( "jetty.thread.queue.size", metric -> @@ -127,7 +116,7 @@ private static MetricsVerifier createMetricsVerifier(int jettyMajorVersion) { .isUpDownCounter() .hasDescription("The current job queue size") .hasUnit("{thread}") - .hasDataPointsWithAttributes(threadPoolAttributes)) + .hasDataPointsWithoutAttributes()) .add( "jetty.select.count", metric -> @@ -135,11 +124,9 @@ private static MetricsVerifier createMetricsVerifier(int jettyMajorVersion) { .isCounter() .hasDescription("The number of select calls") .hasUnit("{operation}") - .hasDataPointsWithAttributes( - attributeGroup( - attributeWithAnyValue("jetty.selector.id"), - attributeWithAnyValue("jetty.selector.context")))); + .hasDataPointsWithoutAttributes()); + AttributeMatcher contextAttribute = attributeWithAnyValue("jetty.context"); if (jettyMajorVersion >= 12) { verifier .add( @@ -149,10 +136,7 @@ private static MetricsVerifier createMetricsVerifier(int jettyMajorVersion) { .isUpDownCounter() .hasDescription("Current number of active sessions") .hasUnit("{session}") - .hasDataPointsWithAttributes( - attributeGroup( - attributeWithAnyValue("jetty.context"), - attributeWithAnyValue("jetty.session.cache.id")))) + .hasDataPointsWithOneAttribute(contextAttribute)) .add( "jetty.session.count.max", metric -> @@ -160,10 +144,7 @@ private static MetricsVerifier createMetricsVerifier(int jettyMajorVersion) { .isGauge() .hasDescription("Maximum number of active sessions") .hasUnit("{session}") - .hasDataPointsWithAttributes( - attributeGroup( - attributeWithAnyValue("jetty.context"), - attributeWithAnyValue("jetty.session.cache.id")))); + .hasDataPointsWithOneAttribute(contextAttribute)); } else { verifier .add( @@ -173,10 +154,7 @@ private static MetricsVerifier createMetricsVerifier(int jettyMajorVersion) { .isCounter() .hasDescription("The total number of created sessions") .hasUnit("{session}") - .hasDataPointsWithAttributes( - attributeGroup( - attributeWithAnyValue("jetty.context"), - attributeWithAnyValue("jetty.session.handler.id")))) + .hasDataPointsWithOneAttribute(contextAttribute)) .add( "jetty.session.duration.sum", metric -> @@ -184,10 +162,7 @@ private static MetricsVerifier createMetricsVerifier(int jettyMajorVersion) { .isCounter() .hasDescription("The cumulated session duration") .hasUnit("s") - .hasDataPointsWithAttributes( - attributeGroup( - attributeWithAnyValue("jetty.context"), - attributeWithAnyValue("jetty.session.handler.id")))) + .hasDataPointsWithOneAttribute(contextAttribute)) .add( "jetty.session.duration.max", metric -> @@ -195,10 +170,7 @@ private static MetricsVerifier createMetricsVerifier(int jettyMajorVersion) { .isGauge() .hasDescription("The maximum session duration") .hasUnit("s") - .hasDataPointsWithAttributes( - attributeGroup( - attributeWithAnyValue("jetty.context"), - attributeWithAnyValue("jetty.session.handler.id")))) + .hasDataPointsWithOneAttribute(contextAttribute)) .add( "jetty.session.duration.mean", metric -> @@ -206,10 +178,7 @@ private static MetricsVerifier createMetricsVerifier(int jettyMajorVersion) { .isGauge() .hasDescription("The mean session duration") .hasUnit("s") - .hasDataPointsWithAttributes( - attributeGroup( - attributeWithAnyValue("jetty.context"), - attributeWithAnyValue("jetty.session.handler.id")))); + .hasDataPointsWithOneAttribute(contextAttribute)); } return verifier; } From 905ea68869d9e6bef9374c77e6f4d3cee972f44f Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Mon, 23 Jun 2025 19:06:35 +0200 Subject: [PATCH 13/15] simplify technical metric attributes --- instrumentation/jmx-metrics/library/jetty.md | 56 ++++++++----------- .../src/main/resources/jmx/rules/jetty.yaml | 25 ++------- 2 files changed, 30 insertions(+), 51 deletions(-) diff --git a/instrumentation/jmx-metrics/library/jetty.md b/instrumentation/jmx-metrics/library/jetty.md index 5f503da77560..7483f5e09298 100644 --- a/instrumentation/jmx-metrics/library/jetty.md +++ b/instrumentation/jmx-metrics/library/jetty.md @@ -10,44 +10,36 @@ The metrics captured and their respective attributes depend on the Jetty version Those metrics require the following Jetty modules to be enabled : `jmx`, `http`, `statistics`, `sessions` and at least one of `ee8-deploy`, `ee9-deploy` or `ee10-deploy`. -| Metric Name | Type | Attributes | Description | -|-------------------------|---------------|--------------------------------------------|-------------------------------------------| -| jetty.thread.count | UpDownCounter | jetty.thread.pool.id, jetty.thread.context | The current number of threads | -| jetty.thread.limit | UpDownCounter | jetty.thread.pool.id, jetty.thread.context | The maximum number of threads in the pool | -| jetty.thread.busy.count | UpDownCounter | jetty.thread.pool.id, jetty.thread.context | The current number of busy threads | -| jetty.thread.idle.count | UpDownCounter | jetty.thread.pool.id, jetty.thread.context | The current number of idle threads | -| jetty.thread.queue.size | UpDownCounter | jetty.thread.pool.id, jetty.thread.context | The current job queue size | -| jetty.io.select.count | Counter | jetty.selector.context, jetty.selector.id | The number of select calls | -| jetty.session.count | UpDownCounter | jetty.context, jetty.session.cache.id | Current number of active sessions | -| jetty.session.count.max | Gauge | jetty.context, jetty.session.cache.id | Maximum number of active sessions | +| Metric Name | Type | Attributes | Description | +|-------------------------|---------------|---------------|-------------------------------------------| +| jetty.thread.count | UpDownCounter | | The current number of threads | +| jetty.thread.limit | UpDownCounter | | The maximum number of threads in the pool | +| jetty.thread.busy.count | UpDownCounter | | The current number of busy threads | +| jetty.thread.idle.count | UpDownCounter | | The current number of idle threads | +| jetty.thread.queue.size | UpDownCounter | | The current job queue size | +| jetty.io.select.count | Counter | | The number of select calls | +| jetty.session.count | UpDownCounter | jetty.context | Current number of active sessions | +| jetty.session.count.max | Gauge | jetty.context | Maximum number of active sessions (*) | - `jetty.context` corresponds to the deployed application subfolder in `webapps` folder. -- `jetty.selector.context` is a technical string identifier, high cardinality with values like `HTTP_1_1@7674f035` but stable per Jetty process instance -- `jetty.selector.id` is a technical numeric identifier, usually with low cardinality between `0` and `9`. -- `jetty.session.cache.id` is a technical numeric identifier, usually single `0` value is used -- `jetty.thread.context` is a technical string identifier, high cardinality with values like `Server@5a411614` but stable per Jetty process instance -- `jetty.thread.pool.id` is a technical numeric identifier, usually single `0` value is used +- `jetty.session.count.max` metric produces unpredictable values when more than one `org.eclipse.jetty.session:context=*,type=defaultsessioncache,id=*` MBean is present, the default Jetty deployment includes a single one. ## Jetty 9 to 11 Those metrics require the following Jetty modules to be enabled : `jmx`, `http` and `stats`. -| Metric Name | Type | Attributes | Description | -|-----------------------------|---------------|-------------------------------------------|-------------------------------------------| -| jetty.thread.count | UpDownCounter | jetty.thread.pool.id | The current number of threads | -| jetty.thread.limit | UpDownCounter | jetty.thread.pool.id | The maximum number of threads in the pool | -| jetty.thread.busy.count | UpDownCounter | jetty.thread.pool.id | The current number of busy threads | -| jetty.thread.idle.count | UpDownCounter | jetty.thread.pool.id | The current number of idle threads | -| jetty.thread.queue.size | UpDownCounter | jetty.thread.pool.id | The current job queue size | -| jetty.io.select.count | Counter | jetty.selector.context, jetty.selector.id | The number of select calls | -| jetty.session.created.count | Counter | jetty.context, jetty.session.handler.id | The total number of created sessions | -| jetty.session.duration.sum | Gauge | jetty.context, jetty.session.handler.id | The cumulated session duration | -| jetty.session.duration.max | Gauge | jetty.context, jetty.session.handler.id | The maximum session duration | -| jetty.session.duration.mean | Gauge | jetty.context, jetty.session.handler.id | The mean session duration | +| Metric Name | Type | Attributes | Description | +|-----------------------------|---------------|---------------|-------------------------------------------| +| jetty.thread.count | UpDownCounter | | The current number of threads | +| jetty.thread.limit | UpDownCounter | | The maximum number of threads in the pool | +| jetty.thread.busy.count | UpDownCounter | | The current number of busy threads | +| jetty.thread.idle.count | UpDownCounter | | The current number of idle threads | +| jetty.thread.queue.size | UpDownCounter | | The current job queue size | +| jetty.io.select.count | Counter | | The number of select calls | +| jetty.session.created.count | Counter | jetty.context | The total number of created sessions | +| jetty.session.duration.sum | Gauge | jetty.context | The cumulated session duration | +| jetty.session.duration.max | Gauge | jetty.context | The maximum session duration | +| jetty.session.duration.mean | Gauge | jetty.context | The mean session duration | - `jetty.context` corresponds to the deployed application subfolder in `webapps` folder. -- `jetty.selector.context` is a technical string identifier, high cardinality with values like `HTTP_1_1@7674f035` but stable per Jetty process instance -- `jetty.selector.id` is a technical numeric identifier, usually with low cardinality between `0` and `9`. -- `jetty.session.cache.id` is a technical numeric identifier, usually single `0` value is used -- `jetty.thread.pool.id` is a technical numeric identifier, usually single `0` value is used -- `jetty.session.handler.id` is a technical numeric identifier, usually single `0` value is used +- `jetty.session.duration.sum`, `jetty.session.duration.max`, `jetty.session.duration.mean` metrics will produce unpredictable results when more than one `org.eclipse.jetty.server.session:context=*,type=sessionhandler,id=*` MBean is present, the default Jetty deployment includes a single one. diff --git a/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml b/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml index 846e4cf6000e..ed6af7519d41 100644 --- a/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml +++ b/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml @@ -3,15 +3,10 @@ rules: # Thread metrics for Jetty 12 and later - bean: org.eclipse.jetty.util.thread:context=*,type=queuedthreadpool,id=* + # usually a single mbean instance exists, thus the metric is aggregated (sum for updowncounter) prefix: jetty.thread. unit: "{thread}" type: updowncounter - metricAttribute: - # 'id' is a "technical ID" with a single '0' value by default - jetty.thread.pool.id: param(id) - # 'context' is a high cardinality value like 'Server@5a411614' but likely stable for the - # duration of the jetty process lifecycle - jetty.thread.context: param(context) mapping: # jetty.thread.count threads: @@ -36,12 +31,10 @@ rules: # Thread metrics for Jetty 9 to 11 - bean: org.eclipse.jetty.util.thread:type=queuedthreadpool,id=* + # usually a single mbean instance exists, thus the metric is aggregated (sum for updowncounter) prefix: jetty.thread. unit: "{thread}" type: updowncounter - metricAttribute: - # 'id' is a "technical ID" with a single '0' value by default - jetty.thread.pool.id: param(id) mapping: # jetty.thread.count threads: @@ -65,12 +58,6 @@ rules: desc: The current job queue size - bean: org.eclipse.jetty.io:context=*,type=managedselector,id=* - metricAttribute: - # 'context' is a high cardinality value like 'HTTP_1_1@7674f035' but likely stable for the - # duration of the jetty process lifecycle - jetty.selector.context: param(context) - # 'id' is a numerical value in [0,9] by default - jetty.selector.id: param(id) mapping: # jetty.select.count selectCount: @@ -81,13 +68,13 @@ rules: # Session metrics for Jetty 12 - bean: org.eclipse.jetty.session:context=*,type=defaultsessioncache,id=* + # usually a single mbean instance exists per context, thus the metric is aggregated: sum for counter, + # gauge metrics will return invalid (last-value) if more than one mbean instance exists. prefix: jetty.session. unit: "{session}" metricAttribute: # 'context' corresponds to the webapp context path jetty.context: param(context) - # 'id' is a "technical ID" with a single '0' value by default - jetty.session.cache.id: param(id) mapping: # jetty.session.count sessionsCurrent: @@ -103,12 +90,12 @@ rules: # Session metrics for Jetty 9 to 11 - bean: org.eclipse.jetty.server.session:context=*,type=sessionhandler,id=* + # usually a single mbean instance exists per context, thus the metric is aggregated: sum for counter, + # gauge metrics will return invalid (last-value) if more than one mbean instance exists. prefix: jetty.session. metricAttribute: # 'context' corresponds to the webapp context path jetty.context: param(context) - # 'id' is a "technical ID" with a single '0' value by default - jetty.session.handler.id: param(id) mapping: # jetty.session.created.count sessionsCreated: From 103b71949fa4ae1ad02466d339310299b655eafa Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Mon, 23 Jun 2025 19:14:02 +0200 Subject: [PATCH 14/15] merge jetty thread metrics --- .../src/main/resources/jmx/rules/jetty.yaml | 36 ++++--------------- 1 file changed, 6 insertions(+), 30 deletions(-) diff --git a/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml b/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml index ed6af7519d41..11276e8dfd12 100644 --- a/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml +++ b/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml @@ -1,36 +1,12 @@ --- rules: - # Thread metrics for Jetty 12 and later - - bean: org.eclipse.jetty.util.thread:context=*,type=queuedthreadpool,id=* - # usually a single mbean instance exists, thus the metric is aggregated (sum for updowncounter) - prefix: jetty.thread. - unit: "{thread}" - type: updowncounter - mapping: - # jetty.thread.count - threads: - metric: count - desc: The current number of threads - # jetty.thread.limit - maxThreads: - metric: limit - desc: The configured maximum number of threads in the pool - # jetty.thread.idle.count - idleThreads: - metric: idle.count - desc: The current number of idle threads - # jetty.thread.busy.count - busyThreads: - metric: busy.count - desc: The current number of busy threads - # jetty.thread.queue.size - queueSize: - metric: queue.size - desc: The current job queue size - - # Thread metrics for Jetty 9 to 11 - - bean: org.eclipse.jetty.util.thread:type=queuedthreadpool,id=* + # Thread metrics + - beans: + # Jetty 12 and later + - org.eclipse.jetty.util.thread:context=*,type=queuedthreadpool,id=* + # Jetty 9 to 11 + - org.eclipse.jetty.util.thread:type=queuedthreadpool,id=* # usually a single mbean instance exists, thus the metric is aggregated (sum for updowncounter) prefix: jetty.thread. unit: "{thread}" From 4299811e55fb93be63f9da5b614a690e7f975e2c Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Fri, 27 Jun 2025 16:44:27 +0200 Subject: [PATCH 15/15] simplify metrics to the reliable ones --- instrumentation/jmx-metrics/library/jetty.md | 7 +--- .../src/main/resources/jmx/rules/jetty.yaml | 30 +++----------- .../jmx/rules/JettyIntegrationTest.java | 41 ++++--------------- 3 files changed, 15 insertions(+), 63 deletions(-) diff --git a/instrumentation/jmx-metrics/library/jetty.md b/instrumentation/jmx-metrics/library/jetty.md index 7483f5e09298..0a5d2fb5d655 100644 --- a/instrumentation/jmx-metrics/library/jetty.md +++ b/instrumentation/jmx-metrics/library/jetty.md @@ -19,10 +19,8 @@ Those metrics require the following Jetty modules to be enabled : `jmx`, `http`, | jetty.thread.queue.size | UpDownCounter | | The current job queue size | | jetty.io.select.count | Counter | | The number of select calls | | jetty.session.count | UpDownCounter | jetty.context | Current number of active sessions | -| jetty.session.count.max | Gauge | jetty.context | Maximum number of active sessions (*) | - `jetty.context` corresponds to the deployed application subfolder in `webapps` folder. -- `jetty.session.count.max` metric produces unpredictable values when more than one `org.eclipse.jetty.session:context=*,type=defaultsessioncache,id=*` MBean is present, the default Jetty deployment includes a single one. ## Jetty 9 to 11 @@ -37,9 +35,6 @@ Those metrics require the following Jetty modules to be enabled : `jmx`, `http` | jetty.thread.queue.size | UpDownCounter | | The current job queue size | | jetty.io.select.count | Counter | | The number of select calls | | jetty.session.created.count | Counter | jetty.context | The total number of created sessions | -| jetty.session.duration.sum | Gauge | jetty.context | The cumulated session duration | -| jetty.session.duration.max | Gauge | jetty.context | The maximum session duration | -| jetty.session.duration.mean | Gauge | jetty.context | The mean session duration | +| jetty.session.duration.sum | Counter | jetty.context | The cumulated session duration | - `jetty.context` corresponds to the deployed application subfolder in `webapps` folder. -- `jetty.session.duration.sum`, `jetty.session.duration.max`, `jetty.session.duration.mean` metrics will produce unpredictable results when more than one `org.eclipse.jetty.server.session:context=*,type=sessionhandler,id=*` MBean is present, the default Jetty deployment includes a single one. diff --git a/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml b/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml index 11276e8dfd12..c40cebbc6eaf 100644 --- a/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml +++ b/instrumentation/jmx-metrics/library/src/main/resources/jmx/rules/jetty.yaml @@ -44,8 +44,9 @@ rules: # Session metrics for Jetty 12 - bean: org.eclipse.jetty.session:context=*,type=defaultsessioncache,id=* - # usually a single mbean instance exists per context, thus the metric is aggregated: sum for counter, - # gauge metrics will return invalid (last-value) if more than one mbean instance exists. + # Usually a single mbean instance exists per context, thus the metric is aggregated: sum for counter, + # gauge metrics will return invalid (last-value) with more than 1 mbean instance, thus none + # is included in this provided configuration. prefix: jetty.session. unit: "{session}" metricAttribute: @@ -57,17 +58,12 @@ rules: metric: count type: updowncounter desc: Current number of active sessions - # jetty.session.count.max - sessionsMax: - metric: count.max - # gauge because it can't be aggregated - type: gauge - desc: Maximum number of active sessions # Session metrics for Jetty 9 to 11 - bean: org.eclipse.jetty.server.session:context=*,type=sessionhandler,id=* - # usually a single mbean instance exists per context, thus the metric is aggregated: sum for counter, - # gauge metrics will return invalid (last-value) if more than one mbean instance exists. + # Usually a single mbean instance exists per context, thus the metric is aggregated: sum for counter, + # gauge metrics will return invalid (last-value) with more than 1 mbean instance, thus none + # is included in this provided configuration. prefix: jetty.session. metricAttribute: # 'context' corresponds to the webapp context path @@ -85,17 +81,3 @@ rules: unit: s type: counter desc: The cumulated session duration - # jetty.session.duration.max - sessionTimeMax: - metric: duration.max - unit: s - # gauge because it can't be aggregated - type: gauge - desc: The maximum session duration - # jetty.session.duration.mean - sessionTimeMean: - metric: duration.mean - unit: s - # gauge because it can't be aggregated - type: gauge - desc: The mean session duration diff --git a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java index 2397977aa9c7..22fd3ad378e3 100644 --- a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java +++ b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/rules/JettyIntegrationTest.java @@ -128,23 +128,14 @@ private static MetricsVerifier createMetricsVerifier(int jettyMajorVersion) { AttributeMatcher contextAttribute = attributeWithAnyValue("jetty.context"); if (jettyMajorVersion >= 12) { - verifier - .add( - "jetty.session.count", - metric -> - metric - .isUpDownCounter() - .hasDescription("Current number of active sessions") - .hasUnit("{session}") - .hasDataPointsWithOneAttribute(contextAttribute)) - .add( - "jetty.session.count.max", - metric -> - metric - .isGauge() - .hasDescription("Maximum number of active sessions") - .hasUnit("{session}") - .hasDataPointsWithOneAttribute(contextAttribute)); + verifier.add( + "jetty.session.count", + metric -> + metric + .isUpDownCounter() + .hasDescription("Current number of active sessions") + .hasUnit("{session}") + .hasDataPointsWithOneAttribute(contextAttribute)); } else { verifier .add( @@ -162,22 +153,6 @@ private static MetricsVerifier createMetricsVerifier(int jettyMajorVersion) { .isCounter() .hasDescription("The cumulated session duration") .hasUnit("s") - .hasDataPointsWithOneAttribute(contextAttribute)) - .add( - "jetty.session.duration.max", - metric -> - metric - .isGauge() - .hasDescription("The maximum session duration") - .hasUnit("s") - .hasDataPointsWithOneAttribute(contextAttribute)) - .add( - "jetty.session.duration.mean", - metric -> - metric - .isGauge() - .hasDescription("The mean session duration") - .hasUnit("s") .hasDataPointsWithOneAttribute(contextAttribute)); } return verifier;