Skip to content

Commit 14cf12a

Browse files
committed
Add JVM/Tomcat contract tests.
1 parent 67f6ca6 commit 14cf12a

File tree

3 files changed

+234
-29
lines changed

3 files changed

+234
-29
lines changed

appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/misc/RuntimeMetricsTest.java

Lines changed: 68 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,28 @@
1717

1818
import static org.assertj.core.api.Assertions.assertThat;
1919

20+
import com.google.common.collect.ImmutableSet;
2021
import io.opentelemetry.proto.metrics.v1.NumberDataPoint;
2122
import java.util.List;
23+
import java.util.Map;
2224
import java.util.Set;
25+
import java.util.function.Consumer;
26+
27+
import org.assertj.core.api.Assertions;
2328
import org.junit.Assert;
2429
import org.junit.jupiter.api.Nested;
2530
import org.junit.jupiter.api.Test;
2631
import org.junit.jupiter.api.TestInstance;
32+
import org.slf4j.Logger;
33+
import org.slf4j.LoggerFactory;
2734
import org.testcontainers.junit.jupiter.Testcontainers;
2835
import software.amazon.opentelemetry.appsignals.test.base.ContractTestBase;
2936
import software.amazon.opentelemetry.appsignals.test.utils.AppSignalsConstants;
37+
import software.amazon.opentelemetry.appsignals.test.utils.JMXMetricsConstants;
3038

3139
public class RuntimeMetricsTest {
3240
private abstract static class RuntimeMetricsContractTestBase extends ContractTestBase {
41+
private static final Logger logger = LoggerFactory.getLogger(RuntimeMetricsContractTestBase.class);
3342
@Override
3443
protected String getApplicationImageName() {
3544
return "aws-appsignals-tests-http-server-spring-mvc";
@@ -53,32 +62,39 @@ protected void doTestRuntimeMetrics() {
5362

5463
protected void assertRuntimeMetrics() {
5564
var metrics =
56-
mockCollectorClient.getRuntimeMetrics(
57-
Set.of(
58-
AppSignalsConstants.JVM_GC_METRIC,
59-
AppSignalsConstants.JVM_GC_COUNT,
60-
AppSignalsConstants.JVM_HEAP_USED,
61-
AppSignalsConstants.JVM_NON_HEAP_USED,
62-
AppSignalsConstants.JVM_AFTER_GC,
63-
AppSignalsConstants.JVM_POOL_USED,
64-
AppSignalsConstants.JVM_THREAD_COUNT,
65-
AppSignalsConstants.JVM_CLASS_LOADED,
66-
AppSignalsConstants.JVM_CPU_TIME,
67-
AppSignalsConstants.JVM_CPU_UTILIZATION,
68-
AppSignalsConstants.LATENCY_METRIC,
69-
AppSignalsConstants.ERROR_METRIC,
70-
AppSignalsConstants.FAULT_METRIC));
65+
mockCollectorClient.getRuntimeMetrics(getExpectedMetrics());
7166
metrics.forEach(
7267
metric -> {
7368
var dataPoints = metric.getMetric().getGauge().getDataPointsList();
74-
assertNonNegativeValue(dataPoints);
69+
logger.info("checking {}: {}", metric.getMetric().getName(), dataPoints.size());
70+
if (JMXMetricsConstants.JVM_MEMORY_USAGE_MAX_METRICS_SET.contains(metric.getMetric().getName())) {
71+
assertGreaterThanOrEqual(dataPoints, -1);
72+
} else {
73+
assertNonNegativeValue(dataPoints);
74+
}
7575
});
7676
}
7777

78+
protected Set<String> getExpectedMetrics() {
79+
return ImmutableSet.<String>builder()
80+
.addAll(JMXMetricsConstants.JVM_METRICS_SET)
81+
.addAll(AppSignalsConstants.SLO_METRICS_SET)
82+
.build();
83+
}
84+
7885
private void assertNonNegativeValue(List<NumberDataPoint> dps) {
86+
assertGreaterThanOrEqual(dps, 0);
87+
}
88+
89+
private void assertGreaterThanOrEqual(List<NumberDataPoint> dps, long threshold) {
90+
assertEachDatapointValue(dps, (value) -> assertThat(value).isGreaterThanOrEqualTo(threshold));
91+
}
92+
93+
private void assertEachDatapointValue(List<NumberDataPoint> dps, Consumer<Long> consumer) {
7994
dps.forEach(
8095
datapoint -> {
81-
Assert.assertTrue(datapoint.getAsInt() >= 0);
96+
logger.info("datapoint value: {}", datapoint.getAsInt());
97+
consumer.accept(datapoint.getAsInt());
8298
});
8399
}
84100
}
@@ -92,4 +108,39 @@ void testRuntimeMetrics() {
92108
doTestRuntimeMetrics();
93109
}
94110
}
111+
112+
@Testcontainers(disabledWithoutDocker = true)
113+
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
114+
@Nested
115+
class ValidateTomcatMetricsTest extends RuntimeMetricsContractTestBase {
116+
@Test
117+
void testTomcatMetrics() {
118+
doTestRuntimeMetrics();
119+
}
120+
121+
@Override
122+
protected Set<String> getExpectedMetrics() {
123+
return ImmutableSet.<String>builder()
124+
.addAll(JMXMetricsConstants.TOMCAT_METRICS_SET)
125+
.addAll(super.getExpectedMetrics())
126+
.build();
127+
}
128+
129+
@Override
130+
protected Map<String, String> getApplicationExtraEnvironmentVariables() {
131+
return Map.of(
132+
"OTEL_JMX_ENABLED", "true",
133+
"OTEL_JMX_TARGET_SYSTEM", "tomcat");
134+
}
135+
136+
@Override
137+
protected String getApplicationImageName() {
138+
return "aws-appsignals-tests-http-server-tomcat";
139+
}
140+
141+
@Override
142+
protected String getApplicationWaitPattern() {
143+
return ".*Starting ProtocolHandler.*";
144+
}
145+
}
95146
}

appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/utils/AppSignalsConstants.java

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
package software.amazon.opentelemetry.appsignals.test.utils;
1717

18+
import java.util.Set;
19+
1820
/***
1921
* Constants for attributes and metric names defined in AppSignals.
2022
*/
@@ -24,6 +26,8 @@ public class AppSignalsConstants {
2426
public static final String ERROR_METRIC = "Error";
2527
public static final String FAULT_METRIC = "Fault";
2628

29+
public static final Set<String> SLO_METRICS_SET = Set.of(LATENCY_METRIC, ERROR_METRIC, FAULT_METRIC);
30+
2731
// Attribute names
2832
public static final String AWS_LOCAL_SERVICE = "aws.local.service";
2933
public static final String AWS_LOCAL_OPERATION = "aws.local.operation";
@@ -33,16 +37,4 @@ public class AppSignalsConstants {
3337
public static final String AWS_REMOTE_RESOURCE_IDENTIFIER = "aws.remote.resource.identifier";
3438
public static final String AWS_SPAN_KIND = "aws.span.kind";
3539
public static final String AWS_REMOTE_DB_USER = "aws.remote.db.user";
36-
37-
// JVM Metrics
38-
public static final String JVM_GC_METRIC = "jvm.gc.collections.elapsed";
39-
public static final String JVM_GC_COUNT = "jvm.gc.collections.count";
40-
public static final String JVM_HEAP_USED = "jvm.memory.heap.used";
41-
public static final String JVM_NON_HEAP_USED = "jvm.memory.nonheap.used";
42-
public static final String JVM_AFTER_GC = "jvm.memory.pool.used_after_last_gc";
43-
public static final String JVM_POOL_USED = "jvm.memory.pool.used";
44-
public static final String JVM_THREAD_COUNT = "jvm.threads.count";
45-
public static final String JVM_CLASS_LOADED = "jvm.classes.loaded";
46-
public static final String JVM_CPU_TIME = "jvm.cpu.time";
47-
public static final String JVM_CPU_UTILIZATION = "jvm.cpu.recent_utilization";
4840
}
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
package software.amazon.opentelemetry.appsignals.test.utils;
2+
3+
import java.util.Set;
4+
5+
public class JMXMetricsConstants {
6+
// JVM Metrics
7+
public static final String JVM_GC_METRIC = "jvm.gc.collections.elapsed";
8+
public static final String JVM_GC_COUNT = "jvm.gc.collections.count";
9+
public static final String JVM_HEAP_INIT = "jvm.memory.heap.init";
10+
public static final String JVM_HEAP_USED = "jvm.memory.heap.used";
11+
public static final String JVM_HEAP_COMMITTED = "jvm.memory.heap.committed";
12+
public static final String JVM_HEAP_MAX = "jvm.memory.heap.max";
13+
public static final String JVM_NON_HEAP_INIT = "jvm.memory.nonheap.init";
14+
public static final String JVM_NON_HEAP_USED = "jvm.memory.nonheap.used";
15+
public static final String JVM_NON_HEAP_COMMITTED = "jvm.memory.nonheap.committed";
16+
public static final String JVM_NON_HEAP_MAX = "jvm.memory.nonheap.max";
17+
public static final String JVM_AFTER_GC = "jvm.memory.pool.used_after_last_gc";
18+
public static final String JVM_POOL_INIT = "jvm.memory.pool.init";
19+
public static final String JVM_POOL_USED = "jvm.memory.pool.used";
20+
public static final String JVM_POOL_COMMITTED = "jvm.memory.pool.committed";
21+
public static final String JVM_POOL_MAX = "jvm.memory.pool.max";
22+
public static final String JVM_THREAD_COUNT = "jvm.threads.count";
23+
public static final String JVM_CLASS_LOADED = "jvm.classes.loaded";
24+
public static final String JVM_CPU_TIME = "jvm.cpu.time";
25+
public static final String JVM_CPU_UTILIZATION = "jvm.cpu.recent_utilization";
26+
27+
public static final Set<String> JVM_METRICS_SET = Set.of(
28+
JVM_GC_METRIC,
29+
JVM_GC_COUNT,
30+
JVM_HEAP_INIT,
31+
JVM_HEAP_USED,
32+
JVM_HEAP_COMMITTED,
33+
JVM_HEAP_MAX,
34+
JVM_NON_HEAP_INIT,
35+
JVM_NON_HEAP_USED,
36+
JVM_NON_HEAP_COMMITTED,
37+
JVM_NON_HEAP_MAX,
38+
JVM_AFTER_GC,
39+
JVM_POOL_INIT,
40+
JVM_POOL_USED,
41+
JVM_POOL_COMMITTED,
42+
JVM_POOL_MAX,
43+
JVM_THREAD_COUNT,
44+
JVM_CLASS_LOADED,
45+
JVM_CPU_TIME,
46+
JVM_CPU_UTILIZATION);
47+
48+
// If maximum memory size is undefined, then value is -1
49+
// https://docs.oracle.com/en/java/javase/17/docs/api/java.management/java/lang/management/MemoryUsage.html#getMax()
50+
public static final Set<String> JVM_MEMORY_USAGE_MAX_METRICS_SET = Set.of(
51+
JVM_HEAP_MAX,
52+
JVM_NON_HEAP_MAX,
53+
JVM_POOL_MAX);
54+
55+
// Tomcat Metrics
56+
public static final String TOMCAT_SESSION = "tomcat.sessions";
57+
public static final String TOMCAT_ERRORS = "tomcat.errors";
58+
public static final String TOMCAT_REQUEST_COUNT = "tomcat.request_count";
59+
public static final String TOMCAT_MAX_TIME = "tomcat.max_time";
60+
public static final String TOMCAT_PROCESSING_TIME = "tomcat.processing_time";
61+
public static final String TOMCAT_TRAFFIC = "tomcat.traffic";
62+
public static final String TOMCAT_THREADS = "tomcat.threads";
63+
64+
public static final Set<String> TOMCAT_METRICS_SET = Set.of(
65+
TOMCAT_SESSION,
66+
TOMCAT_ERRORS,
67+
TOMCAT_REQUEST_COUNT,
68+
TOMCAT_MAX_TIME,
69+
TOMCAT_PROCESSING_TIME,
70+
TOMCAT_TRAFFIC,
71+
TOMCAT_THREADS);
72+
73+
// Kafka Metrics
74+
public static final String KAFKA_MESSAGE_COUNT = "kafka.message.count";
75+
public static final String KAFKA_REQUEST_COUNT = "kafka.request.count";
76+
public static final String KAFKA_REQUEST_FAILED = "kafka.request.failed";
77+
public static final String KAFKA_REQUEST_TIME_TOTAL = "kafka.request.time.total";
78+
public static final String KAFKA_REQUEST_TIME_50P = "kafka.request.time.50p";
79+
public static final String KAFKA_REQUEST_TIME_99P = "kafka.request.time.99p";
80+
public static final String KAFKA_REQUEST_TIME_AVG = "kafka.request.time.avg";
81+
public static final String KAFKA_NETWORK_IO = "kafka.network.io";
82+
public static final String KAFKA_PURGATORY_SIZE = "kafka.purgatory.size";
83+
public static final String KAFKA_PARTITION_COUNT = "kafka.partition.count";
84+
public static final String KAFKA_PARTITION_OFFLINE = "kafka.partition.offline";
85+
public static final String KAFKA_PARTITION_UNDER_REPLICATED = "kafka.partition.under_replicated";
86+
public static final String KAFKA_ISR_OPERATION_COUNT = "kafka.isr.operation.count";
87+
public static final String KAFKA_MAX_LAG = "kafka.max.lag";
88+
public static final String KAFKA_CONTROLLER_ACTIVE_COUNT = "kafka.controller.active.count";
89+
public static final String KAFKA_LEADER_ELECTION_RATE = "kafka.leader.election.rate";
90+
public static final String KAFKA_UNCLEAN_ELECTION_RATE = "kafka.unclean.election.rate";
91+
public static final String KAFKA_REQUEST_QUEUE = "kafka.request.queue";
92+
public static final String KAFKA_LOGS_FLUSH_TIME_COUNT = "kafka.logs.flush.time.count";
93+
public static final String KAFKA_LOGS_FLUSH_TIME_MEDIAN = "kafka.logs.flush.time.median";
94+
public static final String KAFKA_LOGS_FLUSH_TIME_99P = "kafka.logs.flush.time.99p";
95+
96+
public static final Set<String> KAFKA_METRICS_SET = Set.of(
97+
KAFKA_MESSAGE_COUNT,
98+
KAFKA_REQUEST_COUNT,
99+
KAFKA_REQUEST_FAILED,
100+
KAFKA_REQUEST_TIME_TOTAL,
101+
KAFKA_REQUEST_TIME_50P,
102+
KAFKA_REQUEST_TIME_99P,
103+
KAFKA_REQUEST_TIME_AVG,
104+
KAFKA_NETWORK_IO,
105+
KAFKA_PURGATORY_SIZE,
106+
KAFKA_PARTITION_COUNT,
107+
KAFKA_PARTITION_OFFLINE,
108+
KAFKA_PARTITION_UNDER_REPLICATED,
109+
KAFKA_ISR_OPERATION_COUNT,
110+
KAFKA_MAX_LAG,
111+
KAFKA_CONTROLLER_ACTIVE_COUNT,
112+
KAFKA_LEADER_ELECTION_RATE,
113+
KAFKA_UNCLEAN_ELECTION_RATE,
114+
KAFKA_REQUEST_QUEUE,
115+
KAFKA_LOGS_FLUSH_TIME_COUNT,
116+
KAFKA_LOGS_FLUSH_TIME_MEDIAN,
117+
KAFKA_LOGS_FLUSH_TIME_99P);
118+
119+
// Kafka Consumer Metrics
120+
public static final String KAFKA_CONSUMER_FETCH_RATE = "kafka.consumer.fetch-rate";
121+
public static final String KAFKA_CONSUMER_RECORDS_LAG_MAX = "kafka.consumer.records-lag-max";
122+
public static final String KAFKA_CONSUMER_TOTAL_BYTES_CONSUMED_RATE = "kafka.consumer.total.bytes-consumed-rate";
123+
public static final String KAFKA_CONSUMER_TOTAL_FETCH_SIZE_AVG = "kafka.consumer.total.fetch-size-avg";
124+
public static final String KAFKA_CONSUMER_TOTAL_RECORDS_CONSUMED_RATE = "kafka.consumer.total.records-consumed-rate";
125+
public static final String KAFKA_CONSUMER_BYTES_CONSUMED_RATE = "kafka.consumer.bytes-consumed-rate";
126+
public static final String KAFKA_CONSUMER_FETCH_SIZE_AVG = "kafka.consumer.fetch-size-avg";
127+
public static final String KAFKA_CONSUMER_RECORDS_CONSUMED_RATE = "kafka.consumer.records-consumed-rate";
128+
129+
public static final Set<String> KAFKA_CONSUMER_METRICS_SET = Set.of(
130+
KAFKA_CONSUMER_FETCH_RATE,
131+
KAFKA_CONSUMER_RECORDS_LAG_MAX,
132+
KAFKA_CONSUMER_TOTAL_BYTES_CONSUMED_RATE,
133+
KAFKA_CONSUMER_TOTAL_FETCH_SIZE_AVG,
134+
KAFKA_CONSUMER_TOTAL_RECORDS_CONSUMED_RATE,
135+
KAFKA_CONSUMER_BYTES_CONSUMED_RATE,
136+
KAFKA_CONSUMER_FETCH_SIZE_AVG,
137+
KAFKA_CONSUMER_RECORDS_CONSUMED_RATE);
138+
139+
// Kafka Producer Metrics
140+
public static final String KAFKA_PRODUCER_IO_WAIT_TIME_NS_AVG = "kafka.producer.io-wait-time-ns-avg";
141+
public static final String KAFKA_PRODUCER_OUTGOING_BYTE_RATE = "kafka.producer.outgoing-byte-rate";
142+
public static final String KAFKA_PRODUCER_REQUEST_LATENCY_AVG = "kafka.producer.request-latency-avg";
143+
public static final String KAFKA_PRODUCER_REQUEST_RATE = "kafka-producer.request-rate";
144+
public static final String KAFKA_PRODUCER_RESPONSE_RATE = "kafka.producer.response-rate";
145+
public static final String KAFKA_PRODUCER_BYTE_RATE = "kafka.producer.byte-rate";
146+
public static final String KAFKA_PRODUCER_COMPRESSION_RATE = "kafka.producer.compression-rate";
147+
public static final String KAFKA_PRODUCER_RECORD_ERROR_RATE = "kafka.producer.record-error-rate";
148+
public static final String KAFKA_PRODUCER_RECORD_RETRY_RATE = "kafka.producer.record-retry-rate";
149+
public static final String KAFKA_PRODUCER_RECORD_SEND_RATE = "kafka.producer.record-send-rate";
150+
151+
public static final Set<String> KAFKA_PRODUCER_METRICS_SET = Set.of(
152+
KAFKA_PRODUCER_IO_WAIT_TIME_NS_AVG,
153+
KAFKA_PRODUCER_OUTGOING_BYTE_RATE,
154+
KAFKA_PRODUCER_REQUEST_LATENCY_AVG,
155+
KAFKA_PRODUCER_REQUEST_RATE,
156+
KAFKA_PRODUCER_RESPONSE_RATE,
157+
KAFKA_PRODUCER_BYTE_RATE,
158+
KAFKA_PRODUCER_COMPRESSION_RATE,
159+
KAFKA_PRODUCER_RECORD_ERROR_RATE,
160+
KAFKA_PRODUCER_RECORD_RETRY_RATE,
161+
KAFKA_PRODUCER_RECORD_SEND_RATE);
162+
}

0 commit comments

Comments
 (0)