Java용 AWS SDK를 사용하여 CloudWatch로부터 Metrics를 수집해오는 코드로, 해외 사이트에서도 SDK 2.x버전을 비롯하여 구체적으로 작성된 예제가 없어 별도로 작성하게 되었다.

먼저 AWS로 쿼리를 날리기 위해 sdk에서 제공하는 Metric관련 객체로 구체적인 쿼리 내용을 작성한 다음, 다시 Provider를 담은 CloudWatchClient 객체를 통해  요청을 날리게 되는 방식이다.

샘플 코드는 다음과 같다.

 

/* CloudWatch 수집에 필요한 변수 목록 */
String identifier = "InstanceId";
List<String> instanceIds = new ArrayList<>();
instanceIds.add("i-0c194646e304a89ae");
instanceIds.add("i-03800904694d5b060");
String namespace = "AWS/EC2";
String metricName = "CPUUtilization";
int period = 60;
String stat = "Average";

/* CloudWatch 수집 쿼리 실행 시 탐색 시간 범위 */
ZoneId ZONE_ID = ZoneId.of("Asia/Seoul");
int dayRange = 1;
Instant startTimeInstant = LocalDate.now(ZONE_ID).minusDays(dayRange).atStartOfDay(ZONE_ID).toInstant();
Instant endTimeInstant = LocalDate.now(ZONE_ID).atStartOfDay(ZONE_ID).toInstant();

/* Provider 생성을 위한 Credentials */
String accessKey = "xxxxxxxxxx";
String secretKey = "xxxxxxxxxxxxxxxxxxxx";
  • 수집주기(period)의 경우에는 60초로 선언되어 있으나, ec2에 별도로 CloudWatch agent를 설치하고 수집 주기를 설정하지 않았을 경우에는 자동으로 5분마다 수집해온다.
  • startTimeInstant 및 endTimeInstant는 일(day) 단위로 끊기 위해 LocalDate.now().minusDays()를 사용했으나, 그 안의 단위로 범위 지정을 원할 경우 Instant.now().minusSeconds()로 대체한다.

 

/* 쿼리 목록 작성 */
List<MetricDataQuery> metricDataQueryList = new ArrayList<>();
int numbering = 0;
for(String instanceId : instanceIds) {
    Dimension dimension = Dimension.builder().name(identifier).value(instanceId).build(); 
    Metric metric = Metric.builder().namespace(namespace).dimensions(dimension).metricName(metricName).build();
    MetricStat metricStat = MetricStat.builder().metric(metric).period(period).stat(stat).build();
    MetricDataQuery metricDataQuery = MetricDataQuery.builder().metricStat(metricStat).id("m"+(numbering++)).build();
    metricDataQueryList.add(metricDataQuery);
}

  • CloudWatchClient에 대한 Request생성을 위해 최종적으로 필요한 결과물은 1개 이상의 metricDataQuery로, 해당 객체 생성을 위해 Metric, MetricStat을 차례대로 구현하여 파라미터로 추가해야한다.
  • Metric 생성 부분에서 dimension에 대한 setter가 배열 형태로, 하나 이상의 dimension이 추가될 수 있는데, 그 이유는 예를 들어 Target Group를 조회할 경우, ALB 및 TG 각각에 대한 name 및 Id를 요구하므로, 두 개의 dimension을 파라미터로 입력해야 한다. 따라서 그런 예외적인 리소스에 대해 조회하는 경우에는 위 코드를 수정할 필요가 있다.
  • MetricDataQuery는 id가 영어 소문자로 시작되어야 한다.

 

AwsBasicCredentials awsBasicCredentials = AwsBasicCredentials.create(accessKey, secretKey);
AwsCredentialsProvider credentialsProvider = StaticCredentialsProvider.create(awsBasicCredentials);
CloudWatchClient cloudWatchClient = CloudWatchClient.builder().credentialsProvider(credentialsProvider).build();

GetMetricDataRequest request = GetMetricDataRequest.builder().metricDataQueries(metricDataQueryList).startTime(startTimeInstant).endTime(endTimeInstant).build();
GetMetricDataResponse response = cloudWatchClient.getMetricData(request);
  • Credentials를 사용하여 Provider를 생성 및 CloudWatchClient를 통해 Metrics Data요청 결과를 받아온다.

 

List<Instant> timestamps = null;
List<Double> values = null;

for(MetricDataResult result : response.metricDataResults()) {
    timestamps = result.timestamps();
    values = result.values();
    System.out.println(String.format("id : %s", result.id()));
    for (int i=values.size()-1; i>=0; i--) {
        System.out.println(String.format("timestamp : %s, value : %s", timestamps.get(i).atZone(ZONE_ID), values.get(i)));
    }
}

  • response.mtericDataResults()의 사이즈는 MetricDataQuery 리스트의 개수로, 해당 개수만큼 루프를 반복하며 metrics 데이터를 받아온다. 이 안에는 다시 timestamp&value에 대한 리스트를 다시 포함하고 있어 위의 샘플 코드를 실행하면 다음과 같이 출력된다.

     

id : m0
timestamp : 2020-06-22T00:01+09:00[Asia/Seoul], value : 0.40060201907835535
timestamp : 2020-06-22T00:06+09:00[Asia/Seoul], value : 0.4000000000014552
timestamp : 2020-06-22T00:11+09:00[Asia/Seoul], value : 0.4339353524112036
...
timestamp : 2020-06-22T23:46+09:00[Asia/Seoul], value : 0.40003704732945716
timestamp : 2020-06-22T23:51+09:00[Asia/Seoul], value : 0.40063906640635716
timestamp : 2020-06-22T23:56+09:00[Asia/Seoul], value : 0.4333333333343038
id : m1
timestamp : 2020-06-22T00:02+09:00[Asia/Seoul], value : 0.4650828933955702
timestamp : 2020-06-22T00:07+09:00[Asia/Seoul], value : 0.49999999999999983
timestamp : 2020-06-22T00:12+09:00[Asia/Seoul], value : 0.4662128368996522
...
timestamp : 2020-06-22T23:47+09:00[Asia/Seoul], value : 0.49949059924053785
timestamp : 2020-06-22T23:52+09:00[Asia/Seoul], value : 0.5001111419838644
timestamp : 2020-06-22T23:57+09:00[Asia/Seoul], value : 0.5000555709919221