Skip to content

Instantly share code, notes, and snippets.

@phillippelevidad
Created February 13, 2020 19:11
Show Gist options
  • Save phillippelevidad/4943b54fb3139f77538621b635e8c40e to your computer and use it in GitHub Desktop.
Save phillippelevidad/4943b54fb3139f77538621b635e8c40e to your computer and use it in GitHub Desktop.
A quick-start class to pull sumarized costs from your AWS account.
namespace NameIt
{
public static class AwsCostExplorer
{
private const string metricType = "BlendedCost";
private static readonly RegionEndpoint regionEndpoint = RegionEndpoint.USEast1;
public static AwsCostStructure GetCostForAccount(string accessKey, string secretKey, Period period)
{
var client = new AmazonCostExplorerClient(
new BasicAWSCredentials(accessKey, secretKey),
regionEndpoint);
var request = new GetCostAndUsageRequest
{
Granularity = Granularity.MONTHLY,
Metrics = new List<string> { metricType },
GroupBy = new List<GroupDefinition> { new GroupDefinition { Type = "DIMENSION", Key = "SERVICE" } },
TimePeriod = GetTimePeriod(period)
};
var response = client.GetCostAndUsageAsync(request).GetAwaiter().GetResult();
return CostAndUsageConverter.Convert(response);
}
private static DateInterval GetTimePeriod(Period period)
{
var today = DateTime.Today;
var start = period switch
{
Period.MonthToDate => new DateTime(today.Year, today.Month, 1),
Period.Last7Days => today.AddDays(-7d),
Period.Last30Days => today.AddDays(-30d),
_ => throw new IndexOutOfRangeException($"Enum value Period.{period} is not known."),
};
return new DateInterval { Start = start.ToString("yyyy-MM-dd"), End = today.ToString("yyyy-MM-dd") };
}
private static class CostAndUsageConverter
{
public static AwsCostStructure Convert(GetCostAndUsageResponse costAndUsage)
{
var resources = new Dictionary<string, decimal>();
foreach (var group in costAndUsage.ResultsByTime.SelectMany(r => r.Groups))
{
var key = GetGroupKey(group);
var amount = decimal.Parse(group.Metrics[metricType].Amount, CultureInfo.InvariantCulture);
if (resources.ContainsKey(key))
resources[key] += amount;
else resources.Add(key, amount);
}
return new AwsCostStructure(resources);
}
private static string GetGroupKey(Group group)
{
var rawKey = group.Keys.First();
switch (rawKey)
{
case "Amazon CloudFront":
return "CloudFront";
case "EC2 - Other":
case "Amazon Elastic Compute Cloud - Compute":
return "EC2";
case "Amazon Relational Database Service":
return "RDS";
case "Amazon Simple Storage Service":
return "S3";
case "AmazonCloudWatch":
return "CloudWatch";
case "AWS Elemental MediaStore":
case "AWS Key Management Service":
return "Other";
default: return rawKey;
}
}
}
public enum Period
{
MonthToDate,
Last7Days,
Last30Days
}
}
public class AwsCostStructure
{
public AwsCostStructure(IDictionary<string, decimal> costByResources)
{
CostByResources = new ReadOnlyDictionary<string, decimal>(costByResources);
Total = costByResources.Values.Sum();
}
public ReadOnlyDictionary<string, decimal> CostByResources { get; }
public decimal Total { get; }
}
}
@phillippelevidad
Copy link
Author

Usage

As simple as this one-liner:

var costs = AwsCostExplorer.GetCostForAccount(accessKey, secretKey, Period.MonthToDate);

Modify the source to change the AWS Region of resources (defaults to us-east-1, Virginia), and Metric Type (defaults to Blended Costs).

Prints results like this:

{
  "CostByResources": {
    "Other": 0.0000000014,
    "CloudFront": 0.0153310721,
    "EC2": 5.9852594731,
    "RDS": 7.186231321,
    "S3": 0.0046113135,
    "CloudWatch": 0.0,
    "Tax": 0.0
  },
  "Total": 13.1914331811
}

Important

You should first enable the Cost Explorer feature for your account. Log in to the AWS Console, navigate to Account and click the button to enable it under the "Cost Explorer" menu.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment