package com.ipcglobal.awscwxls.cw; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.amazonaws.auth.AWSCredentialsProvider; import com.amazonaws.regions.Region; import com.amazonaws.regions.Regions; import com.amazonaws.services.cloudwatch.AmazonCloudWatchClient; import com.amazonaws.services.cloudwatch.model.Datapoint; import com.amazonaws.services.cloudwatch.model.Dimension; import com.amazonaws.services.cloudwatch.model.GetMetricStatisticsRequest; import com.amazonaws.services.cloudwatch.model.GetMetricStatisticsResult; import com.ipcglobal.awscwxls.main.ExtractItem; import com.ipcglobal.awscwxls.util.Utils; /** * ExtractMetrics calls CloudWatch to extract the Metric|Statistic combinations (i.e. CPUUtilization|Average) by * Namespace (i.e. AWS/EC2) and date/time range */ public class ExtractMetrics { /** The log. */ private static Log log = LogFactory.getLog(ExtractMetrics.class); /** The credentials provider. */ private AWSCredentialsProvider credentialsProvider; /** The CloudWatch client. */ private AmazonCloudWatchClient cwClient; /** The metric names. */ private List<String> metricNames; /** The dimension statistics by metric. */ private Map<String,List<String>> metricStatisticsByMetric; /** The properties. */ private Properties properties; /** * Instantiates a new extract metrics. *dimensionValues. * @param properties the properties * @throws Exception the exception */ public ExtractMetrics( Properties properties ) throws Exception { this.properties = properties; String credentialsProfileName = properties.getProperty("credentialsProfileName").trim(); String credentialsRegion = properties.getProperty("credentialsRegion").trim(); if( credentialsProfileName == null ) this.credentialsProvider = Utils.initCredentials(); else this.credentialsProvider = Utils.initProfileCredentialsProvider( credentialsProfileName ); this.cwClient = new AmazonCloudWatchClient(credentialsProvider); if( credentialsRegion != null ) { Regions regions = Regions.fromName( credentialsRegion ); overrideRegion( regions ); } } /** * Override region. * * @param regions the regions * @throws Exception the exception */ public void overrideRegion( Regions regions ) throws Exception { this.cwClient.setRegion(Region.getRegion( regions )); } /** * Extract metrics by dimension. * * @param extractItem the extract item * @return the list * @throws Exception the exception */ public List<DimensionMetric> extractMetricsByDimension( ExtractItem extractItem ) throws Exception { initStatisticsByMetric( extractItem.getMetricStatisticNames() ); List<DimensionMetric> dimensionMetrics = new ArrayList<DimensionMetric>(); GetMetricStatisticsRequest getMetricRequest = new GetMetricStatisticsRequest(); getMetricRequest.setNamespace( extractItem.getNamespace() ); getMetricRequest.setPeriod( extractItem.getPeriodMinutes() * 60 ); final SimpleDateFormat dfYyyyMmDdHhMmSs = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" ); getMetricRequest.setStartTime( dfYyyyMmDdHhMmSs.parse( properties.getProperty("startTime" ).trim() ) ); getMetricRequest.setEndTime( dfYyyyMmDdHhMmSs.parse( properties.getProperty("endTime").trim() ) ); // Process each DimensionValue (from property dimentionValue.n), i.e. i-1a2b3c4d i-5e6f7g8h for EC2 for( String dimensionValue : extractItem.getDimensionValues() ) { HashMap<Long, MetricSet> metricSets = new HashMap<Long, MetricSet>(); DimensionMetric dimensionMetric = new DimensionMetric().withDimensionValue( dimensionValue ); dimensionMetrics.add( dimensionMetric ); ArrayList<Dimension> dimensions = new ArrayList<Dimension>(); // Create the CloudWatch dimension based on the property dimensionName.n i.e. InstanceId for EC2 dimensions.add(new Dimension().withName( extractItem.getDimensionName() ).withValue( dimensionValue )); getMetricRequest.setDimensions(dimensions); for (String metricName : metricNames ) { log.info( extractItem.getNamespace() + ": dimensionName=" + extractItem.getDimensionName() + ", dimensionValue=" + dimensionValue + ", metric="+metricName ); List<String> statistics = metricStatisticsByMetric.get(metricName); for( String statistic : statistics ) { String metricNameStatisticName = new StringBuilder(metricName).append("|").append(statistic).toString(); dimensionMetric.putDistinctMetricNameStatisticName( metricNameStatisticName ); } getMetricRequest.setStatistics(statistics); getMetricRequest.setMetricName(metricName); GetMetricStatisticsResult getMetricStatisticsResult = cwClient.getMetricStatistics(getMetricRequest); List<Datapoint> datapoints = getMetricStatisticsResult.getDatapoints(); for (Datapoint datapoint : datapoints) { // MetricSet's are keyed by DateTime so that all values for a given DateTime can be output to the // XLS in the same row MetricSet metricSet = metricSets.get(datapoint.getTimestamp().getTime()); if (metricSet == null) { metricSet = new MetricSet(); metricSet.date = datapoint.getTimestamp(); metricSets.put(datapoint.getTimestamp().getTime(), metricSet); } // Set each Metric|Statistic in the MetricSet for( String statistic : statistics ) { String metricNameStatisticName = new StringBuilder(metricName).append("|").append(statistic).toString(); Double value = findStatisticValue( statistic, datapoint); metricSet.setMetricStatisticValue( metricNameStatisticName, value); } } } // Sort the MetricSet to ensure the columns will be output consistently in the XLS ArrayList<MetricSet> sortedMetricSets = new ArrayList<MetricSet>( metricSets.values() ); Collections.sort( sortedMetricSets ); dimensionMetric.setMetricSets( sortedMetricSets ); } return dimensionMetrics; } /** * Inits the statistics by metric. * * @param metricStatisticNames the dimension statistic names * @throws Exception the exception */ private void initStatisticsByMetric( List<String> metricStatisticNames ) throws Exception { metricStatisticsByMetric = new HashMap<String,List<String>>(); for( String metricStatisticName : metricStatisticNames ) { String[] temp = metricStatisticName.split("[|]"); String metricName = temp[0]; String statisticName = temp[1]; List<String> statisticNames = metricStatisticsByMetric.get( metricName ); if( statisticNames == null ) { statisticNames = new ArrayList<String>(); metricStatisticsByMetric.put( metricName, statisticNames ); } statisticNames.add( statisticName ); } metricNames = new ArrayList<String>( metricStatisticsByMetric.keySet() ); Collections.sort( metricNames ); } /** * Find statistic value. * * @param statistic the statistic * @param datapoint the datapoint * @return the double * @throws Exception the exception */ private Double findStatisticValue( String statistic, Datapoint datapoint) throws Exception { if( "Average".equals(statistic) ) return datapoint.getAverage(); else if( "Maximum".equals(statistic) ) return datapoint.getMaximum(); else if( "Minimum".equals(statistic) ) return datapoint.getMinimum(); else if( "Sum".equals(statistic) ) return datapoint.getSum(); else if( "SampleCount".equals(statistic) ) return datapoint.getSampleCount(); else throw new Exception("Invalid statistic: " + statistic); } }