Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
badra001 committed Jan 30, 2026
1 parent 802f8fa commit eee1435
Showing 1 changed file with 80 additions and 0 deletions.
80 changes: 80 additions & 0 deletions local-app/python-tools/billing/aws_monthly_cost.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#!/bin/env python

import boto3
import csv
import datetime
from botocore.exceptions import ClientError

def get_monthly_range(target_date=None):
"""Calculates the start of the current month and the start of the next month."""
if target_date is None:
target_date = datetime.date.today()

# Start of target month
start = target_date.replace(day=1)

# Start of next month (End date is exclusive in AWS API)
if start.month == 12:
end = start.replace(year=start.year + 1, month=1)
else:
end = start.replace(month=start.month + 1)

return start.strftime('%Y-%m-%d'), end.strftime('%Y-%m-%d')

def fetch_aws_costs():
client = boto3.client('ce', region_name='us-east-1') # CE API is us-east-1 only
start_date, end_date = get_monthly_range()

print(f"Fetching costs from {start_date} to {end_date}...")

try:
response = client.get_cost_and_usage(
TimePeriod={'Start': start_date, 'End': end_date},
Granularity='MONTHLY',
Metrics=['BlendedCost', 'UnblendedCost', 'AmortizedCost', 'UsageQuantity'],
GroupBy=[{'Type': 'DIMENSION', 'Key': 'SERVICE'}]
)

rows = []
grand_totals = {'blended': 0.0, 'unblended': 0.0, 'amortized': 0.0}

for group in response['ResultsByTime'][0]['Groups']:
service_name = group['Keys'][0]
metrics = group['Metrics']

# Extracting values
usage_qty = float(metrics['UsageQuantity']['Amount'])
usage_unit = metrics['UsageQuantity']['Unit']
blended = float(metrics['BlendedCost']['Amount'])
unblended = float(metrics['UnblendedCost']['Amount'])
amortized = float(metrics['AmortizedCost']['Amount'])

rows.append([service_name, f"{usage_qty:.2f}", usage_unit, f"{blended:.2f}", f"{unblended:.2f}", f"{amortized:.2f}"])

# Update Grand Totals
grand_totals['blended'] += blended
grand_totals['unblended'] += unblended
grand_totals['amortized'] += amortized

# Sorting by cost (Amortized/Total) descending
rows.sort(key=lambda x: float(x[5]), reverse=True)

# Write to CSV
filename = f"aws_cost_{start_date[:7]}.csv"
with open(filename, 'w', newline='') as f:
writer = csv.writer(f)
writer.writerow(['Service', 'Usage Quantity', 'Unit', 'Blended Cost', 'Unblended Cost', 'Total (Amortized)'])
writer.writerows(rows)
# Grand Total Line
writer.writerow(['GRAND TOTAL', 'NA', 'NA',
f"{grand_totals['blended']:.2f}",
f"{grand_totals['unblended']:.2f}",
f"{grand_totals['amortized']:.2f}"])

print(f"✅ Success! Report saved as {filename}")

except ClientError as e:
print(f"❌ Error: {e}")

if __name__ == "__main__":
fetch_aws_costs()

0 comments on commit eee1435

Please sign in to comment.