Skip to content

Commit 12aec9d

Browse files
Merge pull request #18 from Appdynamics/feature/updating-libraries-and-config-period
Added Java 17 Support, Upgraded dependencies and made period field configurable
2 parents 0cf64e2 + 140ccc7 commit 12aec9d

File tree

11 files changed

+136
-30
lines changed

11 files changed

+136
-30
lines changed

pom.xml

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
<modelVersion>4.0.0</modelVersion>
44
<groupId>com.appdynamics.extensions</groupId>
55
<artifactId>aws-cloudwatch-exts-commons</artifactId>
6-
<version>2.2.7</version>
6+
<version>2.2.8</version>
77
<packaging>jar</packaging>
88

99
<name>aws-cloudwatch-exts-commons</name>
1010

1111
<properties>
1212
<release.repo.local.dir>../maven-repo</release.repo.local.dir>
13+
<aws.sdk.version>2.31.12</aws.sdk.version>
1314
</properties>
1415

1516
<dependencies>
@@ -27,7 +28,7 @@
2728
<dependency>
2829
<groupId>joda-time</groupId>
2930
<artifactId>joda-time</artifactId>
30-
<version>2.3</version>
31+
<version>2.12.5</version>
3132
</dependency>
3233
<dependency>
3334
<groupId>com.fasterxml.woodstox</groupId>
@@ -38,46 +39,46 @@
3839
<dependency>
3940
<groupId>software.amazon.awssdk</groupId>
4041
<artifactId>cloudwatch</artifactId>
41-
<version>2.31.12</version>
42+
<version>${aws.sdk.version}</version>
4243
</dependency>
4344
<dependency>
4445
<groupId>software.amazon.awssdk</groupId>
4546
<artifactId>apache-client</artifactId>
46-
<version>2.31.12</version>
47+
<version>${aws.sdk.version}</version>
4748
</dependency>
4849
<dependency>
4950
<groupId>software.amazon.awssdk</groupId>
5051
<artifactId>sdk-core</artifactId>
51-
<version>2.31.12</version>
52+
<version>${aws.sdk.version}</version>
5253
</dependency>
53-
<dependency>
54+
<!-- <dependency>
5455
<groupId>com.fasterxml.woodstox</groupId>
5556
<artifactId>woodstox-core</artifactId>
5657
<version>7.1.0</version>
57-
</dependency>
58+
</dependency> -->
5859

5960
<dependency>
6061
<groupId>junit</groupId>
6162
<artifactId>junit</artifactId>
62-
<version>4.11</version>
63+
<version>4.13.2</version>
6364
<scope>test</scope>
6465
</dependency>
6566
<dependency>
6667
<groupId>org.powermock</groupId>
67-
<artifactId>powermock-api-mockito</artifactId>
68-
<version>1.4.7</version>
68+
<artifactId>powermock-api-mockito2</artifactId>
69+
<version>2.0.9</version>
6970
<scope>test</scope>
7071
</dependency>
7172
<dependency>
7273
<groupId>org.powermock</groupId>
7374
<artifactId>powermock-module-junit4</artifactId>
74-
<version>1.4.7</version>
75+
<version>2.0.9</version>
7576
<scope>test</scope>
7677
</dependency>
7778
<dependency>
7879
<groupId>org.javassist</groupId>
7980
<artifactId>javassist</artifactId>
80-
<version>3.18.2-GA</version>
81+
<version>3.29.2-GA</version>
8182
<scope>test</scope>
8283
</dependency>
8384
</dependencies>
@@ -87,16 +88,17 @@
8788
<plugin>
8889
<groupId>org.apache.maven.plugins</groupId>
8990
<artifactId>maven-compiler-plugin</artifactId>
90-
<version>2.3.2</version>
91+
<version>3.11.0</version>
9192
<configuration>
92-
<source>1.8</source>
93-
<target>1.8</target>
93+
<source>17</source>
94+
<target>17</target>
9495
</configuration>
9596
</plugin>
9697
<!-- Disabling strict bytecode verification when tests are run to fix the java.lang.VerifyError errors. https://github.com/powermock/powermock/issues/693 -->
9798
<plugin>
9899
<groupId>org.apache.maven.plugins</groupId>
99100
<artifactId>maven-surefire-plugin</artifactId>
101+
<version>3.0.0</version>
100102
<configuration>
101103
<argLine>-noverify</argLine>
102104
<skipTests>true</skipTests>

src/main/java/com/appdynamics/extensions/aws/collectors/AccountMetricStatisticsCollector.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import com.appdynamics.extensions.aws.config.Account;
1111
import com.appdynamics.extensions.aws.config.AwsClientConfig;
1212
import com.appdynamics.extensions.aws.config.CredentialsDecryptionConfig;
13+
import com.appdynamics.extensions.aws.config.MetricsConfig;
1314
import com.appdynamics.extensions.aws.config.MetricsTimeRange;
1415
import com.appdynamics.extensions.aws.config.ProxyConfig;
1516
import com.appdynamics.extensions.aws.exceptions.AwsException;
@@ -24,9 +25,7 @@
2425
import com.google.common.util.concurrent.RateLimiter;
2526
import org.apache.commons.lang3.StringUtils;
2627
import org.slf4j.Logger;
27-
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
2828
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
29-
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
3029

3130

3231
import java.util.List;
@@ -77,6 +76,8 @@ public class AccountMetricStatisticsCollector implements Callable<AccountMetricS
7776

7877
private String metricPrefix;
7978

79+
private MetricsConfig metricsConfig;
80+
8081
private AccountMetricStatisticsCollector(Builder builder) {
8182
this.account = builder.account;
8283
this.noOfMetricThreadsPerRegion = builder.noOfMetricThreadsPerRegion;
@@ -87,6 +88,7 @@ private AccountMetricStatisticsCollector(Builder builder) {
8788
this.rateLimiter = builder.rateLimiter;
8889
this.awsRequestsCounter = builder.awsRequestsCounter;
8990
this.metricPrefix = builder.metricPrefix;
91+
this.metricsConfig = builder.metricsConfig;
9092
this.threadTimeOut = builder.threadTimeOut;
9193

9294
setNoOfRegionThreadsPerAccount(builder.noOfRegionThreadsPerAccount);
@@ -165,6 +167,7 @@ private List<FutureTask<RegionMetricStatistics>> createConcurrentRegionTasks(
165167
.withRateLimiter(rateLimiter)
166168
.withAWSRequestCounter(awsRequestsCounter)
167169
.withPrefix(metricPrefix)
170+
.withMetricsConfig(metricsConfig)
168171
.withAmazonCloudWatchConfig(awsCredentials, awsClientConfig)
169172
.build();
170173

@@ -224,6 +227,7 @@ public static class Builder {
224227
private RateLimiter rateLimiter;
225228
private LongAdder awsRequestsCounter;
226229
private String metricPrefix;
230+
private MetricsConfig metricsConfig;
227231

228232
public Builder withAccount(Account account) {
229233
this.account = account;
@@ -288,6 +292,11 @@ public Builder withThreadTimeOut(int threadTimeOut) {
288292
this.threadTimeOut = threadTimeOut;
289293
return this;
290294
}
295+
296+
public Builder withMetricsConfig(MetricsConfig metricsConfig) {
297+
this.metricsConfig = metricsConfig;
298+
return this;
299+
}
291300
}
292301

293302
}

src/main/java/com/appdynamics/extensions/aws/collectors/MetricStatisticCollector.java

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
package com.appdynamics.extensions.aws.collectors;
99

10+
import com.appdynamics.extensions.aws.config.MetricsConfig;
1011
import com.appdynamics.extensions.aws.config.MetricsTimeRange;
1112
import com.appdynamics.extensions.aws.dto.AWSMetric;
1213
import com.appdynamics.extensions.aws.exceptions.AwsException;
@@ -25,6 +26,7 @@
2526
import java.util.Comparator;
2627
import java.util.Date;
2728
import java.util.List;
29+
import java.util.Optional;
2830
import java.util.concurrent.Callable;
2931
import java.util.concurrent.atomic.LongAdder;
3032

@@ -67,6 +69,8 @@ public class MetricStatisticCollector implements Callable<MetricStatistic> {
6769

6870
private String metricPrefix;
6971

72+
private MetricsConfig metricsConfig;
73+
7074
private MetricStatisticCollector(Builder builder) {
7175

7276
this.accountName = builder.accountName;
@@ -76,6 +80,7 @@ private MetricStatisticCollector(Builder builder) {
7680
this.statType = builder.statType;
7781
this.awsRequestsCounter = builder.awsRequestsCounter;
7882
this.metricPrefix = builder.metricPrefix;
83+
this.metricsConfig = builder.metricsConfig;
7984

8085
//Check if time ranges are specified locally for a metric. If not use the global time ranges.
8186
MetricsTimeRange metricsTimeRangeLocal = metric.getIncludeMetric().getMetricsTimeRange();
@@ -141,11 +146,23 @@ public MetricStatistic call() throws Exception {
141146
}
142147

143148
private GetMetricStatisticsRequest createGetMetricStatisticsRequest() {
149+
// Determine period: metric-specific > global config > default constant
150+
int periodToUse = DEFAULT_METRIC_PERIOD_IN_SEC;
151+
152+
if (metric.getIncludeMetric().getPeriod() > 0) {
153+
periodToUse = metric.getIncludeMetric().getPeriod();
154+
} else if (metricsConfig != null && metricsConfig.getDefaultPeriod() > 0) {
155+
periodToUse = metricsConfig.getDefaultPeriod();
156+
}
157+
158+
// Validate period according to AWS CloudWatch requirements
159+
validatePeriod(periodToUse, startTimeInMinsBeforeNow);
160+
144161
GetMetricStatisticsRequest getMetricStatisticsRequest = GetMetricStatisticsRequest.builder()
145162
.startTime(DateTime.now(DateTimeZone.UTC).minusMinutes(startTimeInMinsBeforeNow).toDate().toInstant())
146163
.namespace(metric.getMetric().namespace())
147164
.dimensions(metric.getMetric().dimensions())
148-
.period(DEFAULT_METRIC_PERIOD_IN_SEC)
165+
.period(periodToUse)
149166
.metricName(metric.getIncludeMetric().getName())
150167
.statistics(statType.asStatistic())
151168
.endTime(DateTime.now(DateTimeZone.UTC).minusMinutes(endTimeInMinsBeforeNow).toDate().toInstant())
@@ -158,11 +175,9 @@ private Datapoint getLatestDatapoint(List<Datapoint> datapoints) {
158175
Datapoint datapoint = null;
159176

160177
if (datapoints != null && !datapoints.isEmpty()) {
161-
if (datapoints.size() > 1) {
162-
Collections.sort(datapoints, new DatapointComparator());
163-
}
164-
165-
datapoint = datapoints.get(0);
178+
Optional<Datapoint> latestDatapoint = datapoints.stream()
179+
.max(Comparator.comparing(this::getTimestamp));
180+
datapoint = latestDatapoint.orElse(null);
166181

167182
} else if (LOGGER.isDebugEnabled()) {
168183
LOGGER.debug(String.format("No statistics retrieved for Namespace [%s] "
@@ -174,6 +189,10 @@ private Datapoint getLatestDatapoint(List<Datapoint> datapoints) {
174189
return datapoint;
175190
}
176191

192+
private Date getTimestamp(Datapoint datapoint) {
193+
return datapoint != null ? Date.from(datapoint.timestamp()) : null;
194+
}
195+
177196
/**
178197
* Descending order comparator for Datapoint
179198
* Null value is always considered last
@@ -238,6 +257,28 @@ private void setEndTimeInMinsBeforeNow(int endTimeInMinsBeforeNow) {
238257
DEFAULT_END_TIME_IN_MINS_BEFORE_NOW : endTimeInMinsBeforeNow;
239258
}
240259

260+
/**
261+
* Validates period according to AWS CloudWatch requirements based on data age
262+
* @param period the period in seconds
263+
* @param startTimeInMinsBeforeNow the start time in minutes before now
264+
*/
265+
private void validatePeriod(int period, int startTimeInMinsBeforeNow) {
266+
if (period <= 0 || period % 60 != 0) {
267+
throw new IllegalArgumentException("Period must be a positive multiple of 60 seconds");
268+
}
269+
270+
// AWS CloudWatch period requirements based on data age
271+
if (startTimeInMinsBeforeNow > 180) { // > 3 hours
272+
if (startTimeInMinsBeforeNow <= 21600 && period < 60) { // 3 hours to 15 days
273+
throw new IllegalArgumentException("For data older than 3 hours, period must be at least 60 seconds");
274+
} else if (startTimeInMinsBeforeNow <= 90720 && period < 300) { // 15 to 63 days
275+
throw new IllegalArgumentException("For data older than 15 days, period must be at least 300 seconds");
276+
} else if (startTimeInMinsBeforeNow > 90720 && period < 3600) { // > 63 days
277+
throw new IllegalArgumentException("For data older than 63 days, period must be at least 3600 seconds");
278+
}
279+
}
280+
}
281+
241282
/**
242283
* Builder class to maintain readability when
243284
* building {@link MetricStatisticCollector} due to its params size
@@ -260,6 +301,8 @@ public static class Builder {
260301

261302
private String metricPrefix;
262303

304+
private MetricsConfig metricsConfig;
305+
263306
public Builder withAccountName(String accountName) {
264307
this.accountName = accountName;
265308
return this;
@@ -304,5 +347,10 @@ public Builder withPrefix(String metricPrefix) {
304347
this.metricPrefix = metricPrefix;
305348
return this;
306349
}
350+
351+
public Builder withMetricsConfig(MetricsConfig metricsConfig) {
352+
this.metricsConfig = metricsConfig;
353+
return this;
354+
}
307355
}
308356
}

src/main/java/com/appdynamics/extensions/aws/collectors/NamespaceMetricStatisticsCollector.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import org.slf4j.Logger;
2727

2828
import java.util.List;
29-
import java.util.Map;
3029
import java.util.concurrent.Callable;
3130
import java.util.concurrent.ExecutionException;
3231
import java.util.concurrent.Executors;
@@ -151,6 +150,7 @@ private List<FutureTask<AccountMetricStatistics>> createConcurrentAccountTasks(
151150
.withRateLimiter(RateLimiter.create(metricsConfig.getGetMetricStatisticsRateLimit()))
152151
.withAWSRequestCounter(awsRequestsCounter)
153152
.withPrefix(metricPrefix)
153+
.withMetricsConfig(metricsConfig)
154154
.build();
155155

156156
FutureTask<AccountMetricStatistics> accountTaskExecutor = new FutureTask<AccountMetricStatistics>(accountTask);

src/main/java/com/appdynamics/extensions/aws/collectors/RegionMetricStatisticsCollector.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
package com.appdynamics.extensions.aws.collectors;
99

1010
import com.appdynamics.extensions.aws.config.AwsClientConfig;
11+
import com.appdynamics.extensions.aws.config.MetricsConfig;
1112
import com.appdynamics.extensions.aws.config.MetricsTimeRange;
1213
import com.appdynamics.extensions.aws.dto.AWSMetric;
1314
import com.appdynamics.extensions.aws.exceptions.AwsException;
@@ -24,11 +25,9 @@
2425
import java.net.URI;
2526
import software.amazon.awssdk.regions.Region;
2627
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
27-
import software.amazon.awssdk.auth.credentials.InstanceProfileCredentialsProvider;
2828
import software.amazon.awssdk.services.cloudwatch.CloudWatchClient;
2929
import software.amazon.awssdk.services.cloudwatch.CloudWatchClientBuilder;
3030

31-
import java.util.Collections;
3231
import java.util.List;
3332
import java.util.concurrent.Callable;
3433
import java.util.concurrent.ExecutionException;
@@ -71,6 +70,8 @@ public class RegionMetricStatisticsCollector implements Callable<RegionMetricSta
7170

7271
private String metricPrefix;
7372

73+
private MetricsConfig metricsConfig;
74+
7475
private RegionMetricStatisticsCollector(Builder builder) {
7576

7677
this.accountName = builder.accountName;
@@ -81,6 +82,7 @@ private RegionMetricStatisticsCollector(Builder builder) {
8182
this.rateLimiter = builder.rateLimiter;
8283
this.awsRequestsCounter = builder.awsRequestsCounter;
8384
this.metricPrefix = builder.metricPrefix;
85+
this.metricsConfig = builder.metricsConfig;
8486
this.threadTimeOut = builder.threadTimeOut;
8587

8688
setNoOfMetricThreadsPerRegion(builder.noOfMetricThreadsPerRegion);
@@ -163,6 +165,7 @@ private List<FutureTask<MetricStatistic>> createConcurrentMetricTasks(MonitorExe
163165
.withStatType(metricsProcessor.getStatisticType(metric))
164166
.withAWSRequestCounter(awsRequestsCounter)
165167
.withPrefix(metricPrefix)
168+
.withMetricsConfig(metricsConfig)
166169
.build();
167170

168171
FutureTask<MetricStatistic> accountTaskExecutor = new FutureTask<MetricStatistic>(metricTask);
@@ -229,6 +232,8 @@ public static class Builder {
229232

230233
private AWSClientCache awsClientCache = AWSClientCache.getInstance();
231234

235+
private MetricsConfig metricsConfig;
236+
232237
public Builder withAccountName(String accountName) {
233238
this.accountName = accountName;
234239
return this;
@@ -310,5 +315,10 @@ public Builder withThreadTimeOut(int threadTimeOut) {
310315
this.threadTimeOut = threadTimeOut;
311316
return this;
312317
}
318+
319+
public Builder withMetricsConfig(MetricsConfig metricsConfig) {
320+
this.metricsConfig = metricsConfig;
321+
return this;
322+
}
313323
}
314324
}

0 commit comments

Comments
 (0)