Skip to content

Commit 63c6172

Browse files
scmacdonrlhagerm
authored andcommitted
rolled in reviewer comments
1 parent 5ef5a23 commit 63c6172

File tree

2 files changed

+60
-33
lines changed

2 files changed

+60
-33
lines changed

javav2/example_code/cloudwatch/src/main/java/com/example/cloudwatch/scenario/CloudWatchActions.java

Lines changed: 47 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
import software.amazon.awssdk.services.cloudwatch.model.SingleMetricAnomalyDetector;
5656
import software.amazon.awssdk.services.cloudwatch.model.StandardUnit;
5757
import software.amazon.awssdk.services.cloudwatch.model.Statistic;
58+
import software.amazon.awssdk.services.cloudwatch.paginators.DescribeAlarmHistoryPublisher;
5859
import software.amazon.awssdk.services.cloudwatch.paginators.ListDashboardsPublisher;
5960
import software.amazon.awssdk.services.cloudwatch.paginators.ListMetricsPublisher;
6061

@@ -82,6 +83,24 @@ public class CloudWatchActions {
8283

8384
private static final Logger logger = LoggerFactory.getLogger(CloudWatchActions.class);
8485

86+
/**
87+
* Retrieves an asynchronous CloudWatch client instance.
88+
*
89+
* <p>
90+
* This method ensures that the CloudWatch client is initialized with the following configurations:
91+
* <ul>
92+
* <li>Maximum concurrency: 100</li>
93+
* <li>Connection timeout: 60 seconds</li>
94+
* <li>Read timeout: 60 seconds</li>
95+
* <li>Write timeout: 60 seconds</li>
96+
* <li>API call timeout: 2 minutes</li>
97+
* <li>API call attempt timeout: 90 seconds</li>
98+
* <li>Retry strategy: STANDARD</li>
99+
* </ul>
100+
* </p>
101+
*
102+
* @return the asynchronous CloudWatch client instance
103+
*/
85104
private static CloudWatchAsyncClient getAsyncClient() {
86105
if (cloudWatchAsyncClient == null) {
87106
SdkAsyncHttpClient httpClient = NettyNioAsyncHttpClient.builder()
@@ -204,7 +223,7 @@ public CompletableFuture<DeleteDashboardsResponse> deleteDashboardAsync(String d
204223
* @param fileName the name of the file to save the metric image to
205224
* @return a {@link CompletableFuture} that completes when the image has been saved to the file
206225
*/
207-
public CompletableFuture<Void> getAndOpenMetricImageAsync(String fileName) {
226+
public CompletableFuture<Void> downloadAndSaveMetricImageAsync(String fileName) {
208227
logger.info("Getting Image data for custom metric.");
209228
String myJSON = """
210229
{
@@ -370,6 +389,7 @@ public CompletableFuture<Void> getAlarmHistoryAsync(String fileName, String date
370389
}
371390
});
372391

392+
// Use the alarm name to describe alarm history with a paginator.
373393
return readFileFuture.thenCompose(alarmName -> {
374394
try {
375395
Instant start = Instant.parse(date);
@@ -381,26 +401,33 @@ public CompletableFuture<Void> getAlarmHistoryAsync(String fileName, String date
381401
.historyItemType(HistoryItemType.ACTION)
382402
.build();
383403

384-
return getAsyncClient().describeAlarmHistory(historyRequest).thenAccept(response -> {
385-
List<AlarmHistoryItem> historyItems = response.alarmHistoryItems();
386-
if (historyItems.isEmpty()) {
387-
logger.info("No alarm history data found for {} ", alarmName);
388-
} else {
389-
for (AlarmHistoryItem item : historyItems) {
390-
logger.info("History summary: {} ", item.historySummary());
391-
logger.info("Timestamp: {}", item.timestamp());
404+
// Use the paginator to paginate through alarm history pages.
405+
DescribeAlarmHistoryPublisher historyPublisher = getAsyncClient().describeAlarmHistoryPaginator(historyRequest);
406+
CompletableFuture<Void> future = historyPublisher
407+
.subscribe(response -> response.alarmHistoryItems().forEach(item -> {
408+
logger.info("History summary: {}", item.historySummary());
409+
logger.info("Timestamp: {}", item.timestamp());
410+
}))
411+
.whenComplete((result, exception) -> {
412+
if (exception != null) {
413+
logger.error("Error occurred while getting alarm history: " + exception.getMessage(), exception);
414+
} else {
415+
logger.info("Successfully retrieved all alarm history.");
392416
}
393-
}
394-
});
417+
});
418+
419+
// Return the future to the calling code for further handling
420+
return future;
395421
} catch (Exception e) {
396422
throw new RuntimeException("Failed to process alarm history", e);
397423
}
398424
}).whenComplete((result, exception) -> {
399425
if (exception != null) {
400-
throw new RuntimeException("Error getting alarm history", exception);
426+
throw new RuntimeException("Error completing alarm history processing", exception);
401427
}
402428
});
403429
}
430+
404431
// snippet-end:[cloudwatch.java2.scenario.get.alarm.history.main]
405432

406433
// snippet-start:[cloudwatch.java2.scenario.check.met.alarm.main]
@@ -664,7 +691,6 @@ public CompletableFuture<Void> describeAlarmsAsync() {
664691
// snippet-end:[cloudwatch.java2.describe_alarms.main]
665692

666693
// snippet-start:[cloudwatch.java2.scenario.create.alarm.main]
667-
668694
/**
669695
* Creates an alarm based on the configuration provided in a JSON file.
670696
*
@@ -673,7 +699,6 @@ public CompletableFuture<Void> describeAlarmsAsync() {
673699
* @throws RuntimeException if an exception occurs while reading the JSON file or creating the alarm
674700
*/
675701
public CompletableFuture<String> createAlarmAsync(String fileName) {
676-
// Handle potential exceptions from reading the file synchronously
677702
com.fasterxml.jackson.databind.JsonNode rootNode;
678703
try {
679704
JsonParser parser = new JsonFactory().createParser(new File(fileName));
@@ -716,7 +741,6 @@ public CompletableFuture<String> createAlarmAsync(String fileName) {
716741
logger.info("Failed to create alarm: {}", ex.getMessage());
717742
throw new RuntimeException("Failed to create alarm", ex);
718743
} else {
719-
// If successful, log and return the alarm name
720744
logger.info("{} was successfully created!", alarmName);
721745
return alarmName;
722746
}
@@ -725,7 +749,6 @@ public CompletableFuture<String> createAlarmAsync(String fileName) {
725749
// snippet-end:[cloudwatch.java2.scenario.create.alarm.main]
726750

727751
// snippet-start:[cloudwatch.java2.scenario.add.metric.dashboard.main]
728-
729752
/**
730753
* Adds a metric to a dashboard asynchronously.
731754
*
@@ -761,6 +784,12 @@ public CompletableFuture<PutDashboardResponse> addMetricToDashboardAsync(String
761784
// snippet-end:[cloudwatch.java2.scenario.add.metric.dashboard.main]
762785

763786
// snippet-start:[cloudwatch.java2.scenario.create.metric.main]
787+
/**
788+
* Creates a new custom metric.
789+
*
790+
* @param dataPoint the data point to be added to the custom metric
791+
* @return a {@link CompletableFuture} representing the asynchronous operation of adding the custom metric
792+
*/
764793
public CompletableFuture<PutMetricDataResponse> createNewCustomMetricAsync(Double dataPoint) {
765794
Dimension dimension = Dimension.builder()
766795
.name("UNIQUE_PAGES")
@@ -797,7 +826,6 @@ public CompletableFuture<PutMetricDataResponse> createNewCustomMetricAsync(Doubl
797826
// snippet-end:[cloudwatch.java2.scenario.create.metric.main]
798827

799828
// snippet-start:[cloudwatch.java2.scenario.list.dashboard.main]
800-
801829
/**
802830
* Lists the available dashboards.
803831
*
@@ -822,15 +850,15 @@ public CompletableFuture<Void> listDashboardsAsync() {
822850
// snippet-start:[cloudwatch.java2.scenario.create.dashboard.main]
823851

824852
/**
825-
* Creates a new dashboard asynchronously with the specified name and metrics from the given file.
853+
* Creates a new dashboard with the specified name and metrics from the given file.
826854
*
827855
* @param dashboardName the name of the dashboard to be created
828856
* @param fileName the name of the file containing the dashboard body
829857
* @return a {@link CompletableFuture} representing the asynchronous operation of creating the dashboard
830858
* @throws IOException if there is an error reading the dashboard body from the file
831859
*/
832860
public CompletableFuture<PutDashboardResponse> createDashboardWithMetricsAsync(String dashboardName, String fileName) throws IOException {
833-
String dashboardBody = readFileAsString(fileName); // Assume this method already throws IOException
861+
String dashboardBody = readFileAsString(fileName);
834862
PutDashboardRequest dashboardRequest = PutDashboardRequest.builder()
835863
.dashboardName(dashboardName)
836864
.dashboardBody(dashboardBody)
@@ -910,7 +938,6 @@ public CompletableFuture<GetMetricStatisticsResponse> getMetricStatisticsAsync(S
910938

911939

912940
// snippet-start:[cloudwatch.java2.scenario.display.metrics.main]
913-
914941
/**
915942
* Retrieves and displays metric statistics for the specified parameters.
916943
*
@@ -961,7 +988,6 @@ public CompletableFuture<GetMetricStatisticsResponse> getAndDisplayMetricStatist
961988
// snippet-end:[cloudwatch.java2.scenario.display.metrics.main]
962989

963990
// snippet-start:[cloudwatch.java2.list_metrics.main]
964-
965991
/**
966992
* Retrieves a list of metric names for the specified namespace.
967993
*
@@ -993,7 +1019,6 @@ public CompletableFuture<ArrayList<String>> listMetsAsync(String namespace) {
9931019
// snippet-end:[cloudwatch.java2.list_metrics.main]
9941020

9951021
// snippet-start:[cloudwatch.java2.scenario.list.namespaces.main]
996-
9971022
/**
9981023
* Lists the available namespaces for the current AWS account.
9991024
*

javav2/example_code/cloudwatch/src/main/java/com/example/cloudwatch/scenario/CloudWatchScenario.java

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@
77
import org.slf4j.Logger;
88
import org.slf4j.LoggerFactory;
99
import software.amazon.awssdk.services.cloudwatch.model.CloudWatchException;
10+
import software.amazon.awssdk.services.cloudwatch.model.DashboardInvalidInputErrorException;
1011
import software.amazon.awssdk.services.cloudwatch.model.DeleteAlarmsResponse;
1112
import software.amazon.awssdk.services.cloudwatch.model.DeleteAnomalyDetectorResponse;
1213
import software.amazon.awssdk.services.cloudwatch.model.DeleteDashboardsResponse;
1314
import software.amazon.awssdk.services.cloudwatch.model.Dimension;
1415
import software.amazon.awssdk.services.cloudwatch.model.GetMetricStatisticsResponse;
16+
import software.amazon.awssdk.services.cloudwatch.model.LimitExceededException;
1517
import software.amazon.awssdk.services.cloudwatch.model.PutDashboardResponse;
1618
import software.amazon.awssdk.services.cloudwatch.model.PutMetricDataResponse;
1719
import java.io.IOException;
@@ -68,11 +70,11 @@ public static void main(String[] args) throws Throwable {
6870
6971
Where:
7072
myDate - The start date to use to get metric statistics. (For example, 2023-01-11T18:35:24.00Z.)\s
71-
costDateWeek - The start date to use to get AWS/Billinget statistics. (For example, 2023-01-11T18:35:24.00Z.)\s
73+
costDateWeek - The start date to use to get AWS/Billing statistics. (For example, 2023-01-11T18:35:24.00Z.)\s
7274
dashboardName - The name of the dashboard to create.\s
73-
dashboardJson - The location of a JSON file to use to create a dashboard. (See jsonWidgets.json in Github.)\s
74-
dashboardAdd - The location of a JSON file to use to update a dashboard. (See CloudDashboard.json in Github.)\s
75-
settings - The location of a JSON file from which various values are read. (See settings.json in Github.)\s
75+
dashboardJson - The location of a JSON file to use to create a dashboard. (See jsonWidgets.json in javav2/example_code/cloudwatch.)\s
76+
dashboardAdd - The location of a JSON file to use to update a dashboard. (See CloudDashboard.json in javav2/example_code/cloudwatch.)\s
77+
settings - The location of a JSON file from which various values are read. (See settings.json in javav2/example_code/cloudwatch.)\s
7678
metricImage - The location of a BMP file that is used to create a graph.\s
7779
""";
7880

@@ -287,8 +289,8 @@ private static void runScenario(String myDate, String costDateWeek, String dashb
287289

288290
} catch (RuntimeException | IOException rt) {
289291
Throwable cause = rt.getCause();
290-
if (cause instanceof CloudWatchException cwEx) {
291-
logger.info("CloudWatch error occurred: Error message: {}, Error code {}", cwEx.getMessage(), cwEx.awsErrorDetails().errorCode());
292+
if (cause instanceof DashboardInvalidInputErrorException cwEx) {
293+
logger.info("Invalid CloudWatch data. Error message: {}, Error code {}", cwEx.getMessage(), cwEx.awsErrorDetails().errorCode());
292294
} else {
293295
logger.info("An unexpected error occurred: {}", rt.getMessage());
294296
}
@@ -348,8 +350,8 @@ private static void runScenario(String myDate, String costDateWeek, String dashb
348350

349351
} catch (RuntimeException rt) {
350352
Throwable cause = rt.getCause();
351-
if (cause instanceof CloudWatchException cwEx) {
352-
logger.info("CloudWatch error occurred: Error message: {}, Error code {}", cwEx.getMessage(), cwEx.awsErrorDetails().errorCode());
353+
if (cause instanceof DashboardInvalidInputErrorException cwEx) {
354+
logger.info("Invalid CloudWatch data. Error message: {}, Error code {}", cwEx.getMessage(), cwEx.awsErrorDetails().errorCode());
353355
} else {
354356
logger.info("An unexpected error occurred: {}", rt.getMessage());
355357
}
@@ -367,8 +369,8 @@ private static void runScenario(String myDate, String costDateWeek, String dashb
367369

368370
} catch (RuntimeException rt) {
369371
Throwable cause = rt.getCause();
370-
if (cause instanceof CloudWatchException cwEx) {
371-
logger.info("CloudWatch error occurred: Error message: {}, Error code {}", cwEx.getMessage(), cwEx.awsErrorDetails().errorCode());
372+
if (cause instanceof LimitExceededException cwEx) {
373+
logger.info("The quota for alarms has been reached: Error message: {}, Error code {}", cwEx.getMessage(), cwEx.awsErrorDetails().errorCode());
372374
} else {
373375
logger.info("An unexpected error occurred: {}", rt.getMessage());
374376
}
@@ -521,7 +523,7 @@ private static void runScenario(String myDate, String costDateWeek, String dashb
521523
logger.info(DASHES);
522524
logger.info("17. Get a metric image for the custom metric.");
523525
try {
524-
CompletableFuture<Void> future = cwActions.getAndOpenMetricImageAsync(metricImage);
526+
CompletableFuture<Void> future = cwActions.downloadAndSaveMetricImageAsync(metricImage);
525527
future.join();
526528

527529
} catch (RuntimeException rt) {

0 commit comments

Comments
 (0)