Skip to content

Commit 6897982

Browse files
Merge pull request #16 from Appdynamics/feature/java_upgrade_and_api_pathwise_metrics
Java upgrade and api pathwise metrics
2 parents 716e055 + 3bcf18c commit 6897982

File tree

8 files changed

+156
-84
lines changed

8 files changed

+156
-84
lines changed

README.md

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,36 @@ More details around metric prefix can be found [here](https://community.appdynam
5252
regions: ["eu-central-1","eu-west-1"]
5353
~~~
5454

55-
3. Provide the list of Api names that needs to be monitored. This list accepts regular expressions.
55+
3. Provide the list of Api Ids that needs to be monitored. This list accepts regular expressions. (Previously api names were expected but the field has been deprecated)
5656

5757
~~~
58-
apiNames: ["api1", "api2"]
58+
apiId: ["api1", "api2"]
5959
~~~
6060

61+
4. Configure the `metricsConfig` section to control how metrics are collected from CloudWatch:
62+
63+
**metricsTimeRange**: Controls the time window for metric collection
64+
- `startTimeInMinsBeforeNow`: How many minutes back from current time to start collecting metrics (default: 60)
65+
- `endTimeInMinsBeforeNow`: How many minutes back from current time to end collecting metrics (default: 0, meaning current time)
66+
67+
**getMetricStatisticsRateLimit**: Rate limit per second for CloudWatch GetMetricStatistics API calls (default: 400).
68+
This helps avoid hitting AWS API throttling limits. See [AWS CloudWatch limits](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch_limits.html) for more details.
69+
70+
**maxErrorRetrySize**: Maximum number of retry attempts for failed requests or throttling errors (default: 0, meaning no retries).
71+
72+
**defaultPeriod**: Default time period in seconds for all metrics. Must be a multiple of 60 (default: 300).
73+
Valid values include 60, 300, 3600, etc. Individual metrics can override this using the 'period' field in their specific configuration.
74+
75+
~~~
76+
metricsConfig:
77+
metricsTimeRange:
78+
startTimeInMinsBeforeNow: 60
79+
endTimeInMinsBeforeNow: 0
80+
getMetricStatisticsRateLimit: 400
81+
maxErrorRetrySize: 0
82+
defaultPeriod: 300
83+
~~~
84+
6185
## Metrics
6286

6387
1. 4XXError - The number of client-side errors captured in a specified period.

pom.xml

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@
2626
<dependency>
2727
<groupId>com.appdynamics.extensions</groupId>
2828
<artifactId>aws-cloudwatch-exts-commons</artifactId>
29-
<version>2.2.5</version>
29+
<version>2.2.8</version>
3030
</dependency>
3131
<dependency>
3232
<groupId>com.amazonaws</groupId>
3333
<artifactId>aws-java-sdk-api-gateway</artifactId>
34-
<version>1.11.642</version>
34+
<version>1.12.788</version>
3535
</dependency>
3636
<dependency>
3737
<groupId>junit</groupId>
@@ -40,15 +40,15 @@
4040
<scope>test</scope>
4141
</dependency>
4242
<dependency>
43-
<groupId>org.powermock</groupId>
44-
<artifactId>powermock-api-mockito</artifactId>
45-
<version>1.7.3</version>
43+
<groupId>org.mockito</groupId>
44+
<artifactId>mockito-core</artifactId>
45+
<version>4.11.0</version>
4646
<scope>test</scope>
4747
</dependency>
4848
<dependency>
49-
<groupId>org.powermock</groupId>
50-
<artifactId>powermock-module-junit4</artifactId>
51-
<version>1.7.3</version>
49+
<groupId>org.mockito</groupId>
50+
<artifactId>mockito-inline</artifactId>
51+
<version>4.11.0</version>
5252
<scope>test</scope>
5353
</dependency>
5454
</dependencies>
@@ -59,10 +59,30 @@
5959
<plugin>
6060
<groupId>org.apache.maven.plugins</groupId>
6161
<artifactId>maven-compiler-plugin</artifactId>
62-
<version>2.3.2</version>
62+
<version>3.14.0</version>
6363
<configuration>
64-
<source>1.8</source>
65-
<target>1.8</target>
64+
<source>17</source>
65+
<target>17</target>
66+
</configuration>
67+
</plugin>
68+
<plugin>
69+
<groupId>org.apache.maven.plugins</groupId>
70+
<artifactId>maven-surefire-plugin</artifactId>
71+
<version>3.1.2</version>
72+
<configuration>
73+
<argLine>
74+
--add-opens java.base/jdk.internal.reflect=ALL-UNNAMED
75+
--add-opens java.base/java.util=ALL-UNNAMED
76+
--add-opens java.base/java.lang=ALL-UNNAMED
77+
--add-opens java.base/java.lang.reflect=ALL-UNNAMED
78+
--add-opens java.base/java.lang.invoke=ALL-UNNAMED
79+
--add-opens java.base/java.util.regex=ALL-UNNAMED
80+
--add-opens java.base/java.util.concurrent.atomic=ALL-UNNAMED
81+
--add-opens java.base/java.io=ALL-UNNAMED
82+
--add-opens java.base/java.xml=ALL-UNNAMED
83+
--add-exports java.xml/jdk.xml.internal=ALL-UNNAMED
84+
--add-opens java.base/java.util.stream=ALL-UNNAMED
85+
</argLine>
6686
</configuration>
6787
</plugin>
6888
<plugin>
@@ -133,7 +153,7 @@
133153
<fileset dir="${project.basedir}" includes="LICENSE.txt" />
134154
</copy>
135155
<copy todir="${target.dir}">
136-
<fileset dir="${build.directory}" includes="${project.artifactId}.${project.packaging}" />
156+
<fileset dir="${project.build.directory}" includes="${project.artifactId}.${project.packaging}" />
137157
</copy>
138158
<zip destfile="${target.dir}-${project.version}.zip">
139159
<zipfileset dir="${target.dir}" filemode="755" prefix="${target.name}/" />

src/main/java/com/appdynamics/extensions/aws/apigateway/ApiNamesPredicate.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
package com.appdynamics.extensions.aws.apigateway;
1717

1818

19-
import com.amazonaws.services.cloudwatch.model.Metric;
19+
import software.amazon.awssdk.services.cloudwatch.model.Metric;
2020
import com.google.common.base.Predicate;
2121
import com.google.common.base.Predicates;
2222
import com.google.common.base.Strings;
@@ -28,18 +28,18 @@
2828
*/
2929
public class ApiNamesPredicate implements Predicate<Metric> {
3030

31-
private List<String> apiNamesList;
31+
private List<String> apiIdList;
3232
private Predicate<CharSequence> patternPredicate;
3333

34-
public ApiNamesPredicate(List<String> apiNamesList){
35-
this.apiNamesList = apiNamesList;
34+
public ApiNamesPredicate(List<String> apiIdList){
35+
this.apiIdList = apiIdList;
3636
buildPattern();
3737
}
3838

3939
private void buildPattern(){
40-
if(apiNamesList != null && !apiNamesList.isEmpty()){
40+
if(apiIdList != null && !apiIdList.isEmpty()){
4141

42-
for(String apiPattern : apiNamesList){
42+
for(String apiPattern : apiIdList){
4343
if(!Strings.isNullOrEmpty(apiPattern)) {
4444
Predicate<CharSequence> apiPatternPredicate = Predicates.containsPattern(apiPattern);
4545
if (patternPredicate == null) {
@@ -58,7 +58,7 @@ public boolean apply(Metric metric) {
5858
return true;
5959
}
6060
else{
61-
String apiName = metric.getDimensions().get(0).getValue();
61+
String apiName = metric.dimensions().get(0).value();
6262
return patternPredicate.apply(apiName);
6363
}
6464
}

src/main/java/com/appdynamics/extensions/aws/apigateway/configuration/APIGatewayConfiguration.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
public class APIGatewayConfiguration extends Configuration {
2828

2929
private Map<String, ?> eventsService;
30-
private List<String> apiNames;
30+
private List<String> apiId;
3131

3232

3333
public void setEventsService(Map<String, ?> eventsService) {
@@ -38,11 +38,11 @@ public void setEventsService(Map<String, ?> eventsService) {
3838
return eventsService;
3939
}
4040

41-
public void setApiNames(List<String> apiNames) {
42-
this.apiNames = apiNames;
41+
public void setApiId(List<String> apiId) {
42+
this.apiId = apiId;
4343
}
4444

45-
public List<String> getApiNames() {
46-
return apiNames;
45+
public List<String> getApiId() {
46+
return apiId;
4747
}
4848
}

src/main/java/com/appdynamics/extensions/aws/apigateway/processors/APIGatewayMetricsProcessor.java

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@
1515

1616
package com.appdynamics.extensions.aws.apigateway.processors;
1717

18-
import com.amazonaws.services.cloudwatch.AmazonCloudWatch;
19-
import com.amazonaws.services.cloudwatch.model.Dimension;
20-
import com.amazonaws.services.cloudwatch.model.DimensionFilter;
18+
import software.amazon.awssdk.services.cloudwatch.CloudWatchClient;
19+
import software.amazon.awssdk.services.cloudwatch.model.Dimension;
20+
import software.amazon.awssdk.services.cloudwatch.model.DimensionFilter;
2121
import com.appdynamics.extensions.aws.apigateway.ApiNamesPredicate;
2222
import com.appdynamics.extensions.aws.apigateway.EventsServiceMetricsWriter;
2323
import com.appdynamics.extensions.aws.apigateway.configuration.APIGatewayConfiguration;
24-
import com.appdynamics.extensions.aws.apigateway.configuration.EventsService;
24+
2525
import com.appdynamics.extensions.aws.config.IncludeMetric;
2626
import com.appdynamics.extensions.aws.dto.AWSMetric;
2727
import com.appdynamics.extensions.aws.metric.*;
@@ -31,6 +31,9 @@
3131
import com.appdynamics.extensions.metrics.Metric;
3232
import com.google.common.collect.Lists;
3333
import com.google.common.collect.Maps;
34+
35+
36+
3437
import org.slf4j.Logger;
3538

3639

@@ -47,20 +50,21 @@ public class APIGatewayMetricsProcessor implements MetricsProcessor {
4750
private static final Logger logger = ExtensionsLoggerFactory.getLogger(APIGatewayMetricsProcessor.class);
4851
private static final String NAMESPACE = "AWS/ApiGateway";
4952
private static final String APINAME = "ApiName";
53+
private static final String APIID = "ApiId";
5054
private List<IncludeMetric> includeMetrics;
51-
private List<String> apiNamesList;
55+
private List<String> apiIdList;
5256
private APIGatewayConfiguration apiGatewayConfiguration;
5357
private Map<String, ?> eventsService;
5458

5559
public APIGatewayMetricsProcessor(APIGatewayConfiguration apiGatewayConfiguration){
5660
this.apiGatewayConfiguration = apiGatewayConfiguration;
5761
this.includeMetrics = apiGatewayConfiguration.getMetricsConfig().getIncludeMetrics();
58-
this.apiNamesList = apiGatewayConfiguration.getApiNames();
62+
this.apiIdList = apiGatewayConfiguration.getApiId();
5963
this.eventsService = apiGatewayConfiguration.getEventsService();
6064
}
6165

6266
@Override
63-
public List<AWSMetric> getMetrics(AmazonCloudWatch awsCloudWatch, String accountName, LongAdder awsRequestsCounter) {
67+
public List<AWSMetric> getMetrics(CloudWatchClient cloudWatchClient, String accountName, LongAdder awsRequestsCounter) {
6468
/*The dimension being used here for filtering is "ApiName".
6569
* Another available dimension is "ApiName" and "Stage".
6670
* The "ApiName" dimension filter will retrieve metrics with just the
@@ -75,20 +79,30 @@ public List<AWSMetric> getMetrics(AmazonCloudWatch awsCloudWatch, String account
7579
* Since the dimension used for filtering is "ApiName", we can filter
7680
* further with the ApiName values.
7781
* */
78-
ApiNamesPredicate apiNamesPredicate = new ApiNamesPredicate(apiNamesList);
82+
ApiNamesPredicate apiNamesPredicate = new ApiNamesPredicate(apiIdList);
7983

80-
return MetricsProcessorHelper.getFilteredMetrics(awsCloudWatch, awsRequestsCounter, NAMESPACE, includeMetrics, dimensionFilters, apiNamesPredicate);
84+
return MetricsProcessorHelper.getFilteredMetrics(cloudWatchClient, awsRequestsCounter, NAMESPACE, includeMetrics, dimensionFilters, apiNamesPredicate);
8185
}
8286

8387
private List<DimensionFilter> getDimensionFilters(){
8488
List<DimensionFilter> dimensionFilters = Lists.newArrayList();
8589

86-
DimensionFilter apiNameDimensionFilter = new DimensionFilter();
87-
apiNameDimensionFilter.withName(APINAME);
90+
DimensionFilter apiNameDimensionFilter = DimensionFilter.builder()
91+
.name(APIID)
92+
.build();
93+
DimensionFilter resourceNameDimensionFilter = DimensionFilter.builder()
94+
.name("Resource")
95+
.build();
96+
DimensionFilter stageNameDimensionFilter = DimensionFilter.builder()
97+
.name("Stage")
98+
.build();
99+
88100
dimensionFilters.add(apiNameDimensionFilter);
101+
dimensionFilters.add(stageNameDimensionFilter);
102+
dimensionFilters.add(resourceNameDimensionFilter);
89103

90104
/*DimensionFilter stageDimensionFilter = new DimensionFilter();
91-
stageDimensionFilter.withName("Stage");
105+
stageDimensionFilter.setName("Stage");
92106
dimensionFilters.add(stageDimensionFilter);*/
93107

94108
return dimensionFilters;
@@ -148,16 +162,20 @@ private void uploadToEventsServiceIfEnabled(List<Metric> metricList){
148162
private String createMetricPath(String accountName, String region, MetricStatistic metricStatistic){
149163
AWSMetric awsMetric = metricStatistic.getMetric();
150164
IncludeMetric includeMetric = awsMetric.getIncludeMetric();
151-
com.amazonaws.services.cloudwatch.model.Metric metric = awsMetric.getMetric();
165+
software.amazon.awssdk.services.cloudwatch.model.Metric metric = awsMetric.getMetric();
152166
String apiName = null;
153167
String stageName = null;
168+
String routeName = null;
154169

155-
for(Dimension dimension : metric.getDimensions()) {
156-
if(dimension.getName().equalsIgnoreCase("ApiName")) {
157-
apiName = dimension.getValue();
170+
for(Dimension dimension : metric.dimensions()) {
171+
if(dimension.name().equalsIgnoreCase("ApiId")) {
172+
apiName = dimension.value();
173+
}
174+
if(dimension.name().equalsIgnoreCase("Stage")) {
175+
stageName = dimension.value();
158176
}
159-
if(dimension.getName().equalsIgnoreCase("Stage")) {
160-
stageName = dimension.getValue();
177+
if(dimension.name().equalsIgnoreCase("Resource")) {
178+
routeName = dimension.value();
161179
}
162180
}
163181
//apiName will never be null
@@ -171,7 +189,12 @@ private String createMetricPath(String accountName, String region, MetricStatist
171189
stringBuilder.append(stageName)
172190
.append("|");
173191
}
192+
if(routeName != null) {
193+
stringBuilder.append(routeName)
194+
.append("|");
195+
}
174196
stringBuilder.append(includeMetric.getName());
197+
logger.info(stringBuilder.toString());
175198
return stringBuilder.toString();
176199

177200
}

src/main/resources/conf/config.yml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ accounts:
2424
displayAccountName: "AppD"
2525
regions: ["us-west-2"]
2626

27-
apiNames: []
27+
apiId: []
2828

2929
metricsConfig:
3030
# Global time range configuration, applicable to all the metrics configured below.
@@ -36,6 +36,10 @@ metricsConfig:
3636
# The max number of retry attempts for failed retryable requests
3737
# (ex: 5xx error responses from a service) or throttling errors
3838
maxErrorRetrySize: 0
39+
# Default period for all metrics (in seconds). Must be a multiple of 60.
40+
# Valid values: 60, 300, 3600, etc.
41+
# Individual metrics can override this value using the 'period' field in the specific includeMetrics section
42+
defaultPeriod: 300
3943
# By default, all metrics retrieved from cloudwatch are 'Average' values.
4044
# This option allows you to override the metric type.
4145
# Allowed statTypes are: ave, max, min, sum, samplecount
@@ -53,9 +57,6 @@ metricsConfig:
5357
multiplier: 1
5458
timeRollUpType: "AVERAGE"
5559
clusterRollUpType: "INDIVIDUAL"
56-
metricsTimeRange:
57-
startTimeInMinsBeforeNow: 10
58-
endTimeInMinsBeforeNow: 0
5960
- name: "5XXError"
6061
alias: "5XXError"
6162
statType: "ave"
@@ -103,6 +104,7 @@ regionEndPoints:
103104
ap-northeast-1: monitoring.ap-northeast-1.amazonaws.com
104105
ap-southeast-1: monitoring.ap-southeast-1.amazonaws.com
105106
ap-southeast-2: monitoring.ap-southeast-2.amazonaws.com
107+
ap-south-1: monitoring.ap-south-1.amazonaws.com
106108
eu-central-1: monitoring.eu-central-1.amazonaws.com
107109
us-east-1: monitoring.us-east-1.amazonaws.com
108110
us-west-1: monitoring.us-west-1.amazonaws.com

0 commit comments

Comments
 (0)