-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
216 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
# AWS Cost Monitoring Package | ||
|
||
This package provides tools for monitoring and analyzing AWS costs, both at the organizational level and individual account level. It includes functionality to get detailed cost breakdowns by linked accounts and AWS services, along with visualizations. | ||
This package provides tools for monitoring and analyzing AWS costs, both at the organizational level and individual account level. It includes functionality to get detailed cost breakdowns by linked accounts, AWS services, and regions, along with visualizations and alerting. | ||
|
||
## Installation | ||
|
||
|
@@ -86,30 +86,94 @@ Displays a bar graph of the cost per AWS service within the specified time perio | |
def get_cost_per_service_graph(self, start: str, end: str, linked_account: str = None): | ||
``` | ||
|
||
### Example Usage | ||
#### Generate Customizable Reports | ||
|
||
Generates customizable reports of AWS costs. | ||
|
||
```python | ||
def generate_report(self, start: str, end: str, granularity: str, metrics: list, group_by: list = [], report_type: str = 'csv', file_name: str = 'aws_cost_report') -> None: | ||
``` | ||
|
||
- **start**: Start date in `YYYY-MM-DD` format. | ||
- **end**: End date in `YYYY-MM-DD` format. | ||
- **granularity**: Granularity of the data (DAILY, MONTHLY). | ||
- **metrics**: List of metrics to fetch (e.g., ['UNBLENDED_COST']). | ||
- **group_by**: List of dimensions to group by. | ||
- **report_type**: Type of the report to generate ('csv' or 'json'). | ||
- **file_name**: Name of the report file. | ||
|
||
#### Get Cost Per Region | ||
|
||
Fetches the cost per AWS region within the specified time period. | ||
|
||
```python | ||
def get_cost_per_region(self, start: str, end: str) -> dict: | ||
``` | ||
|
||
#### Get Cost Per Region Graph | ||
|
||
Displays a bar graph of the cost per AWS region within the specified time period. | ||
|
||
```python | ||
def get_cost_per_region_graph(self, start: str, end: str): | ||
``` | ||
|
||
#### Set Cost Alert | ||
|
||
Sets an alert for AWS costs and sends an email notification if the cost exceeds the specified threshold. | ||
|
||
```python | ||
def set_cost_alert(self, start: str, end: str, threshold: float, email: str, granularity: str = 'MONTHLY'): | ||
``` | ||
|
||
- **start**: Start date in `YYYY-MM-DD` format. | ||
- **end**: End date in `YYYY-MM-DD` format. | ||
- **threshold**: Cost threshold for the alert. | ||
- **email**: Email address to send the alert. | ||
- **granularity**: Granularity of the data (DAILY, MONTHLY). | ||
|
||
## Example | ||
|
||
Here is a basic example of how to use the `AWSOrgMonitor` class: | ||
|
||
```python | ||
from aws_monitoring.utils import AWSOrgMonitor | ||
|
||
monitor = AWSOrgMonitor() | ||
start_date = '2023-06-01' | ||
end_date = '2023-06-30' | ||
|
||
# Get cost per service | ||
service_costs = monitor.get_cost_per_service(start_date, end_date) | ||
print(service_costs) | ||
# Get cost data | ||
cost_data = monitor.get_cost(start='2023-01-01', end='2023-01-31', granularity='MONTHLY', metrics=['UNBLENDED_COST']) | ||
print(cost_data) | ||
|
||
# Visualize cost per service | ||
monitor.get_cost_per_service_graph(start_date, end_date) | ||
# Get billed accounts | ||
billed_accounts = monitor.get_billed_accounts(start='2023-01-01', end='2023-01-31') | ||
print(billed_accounts) | ||
|
||
# Get cost per account | ||
account_costs = monitor.get_cost_per_account(start_date, end_date) | ||
print(account_costs) | ||
cost_per_account = monitor.get_cost_per_account(start='2023-01-01', end='2023-01-31') | ||
print(cost_per_account) | ||
|
||
# Display cost per account graph | ||
monitor.get_cost_per_account_graph(start='2023-01-01', end='2023-01-31') | ||
|
||
# Get cost per service | ||
cost_per_service = monitor.get_cost_per_service(start='2023-01-01', end='2023-01-31') | ||
print(cost_per_service) | ||
|
||
# Visualize cost per account | ||
monitor.get_cost_per_account_graph(start_date, end_date) | ||
# Display cost per service graph | ||
monitor.get_cost_per_service_graph(start='2023-01-01', end='2023-01-31') | ||
|
||
# Generate a report | ||
monitor.generate_report(start='2023-01-01', end='2023-01-31', granularity='MONTHLY', metrics=['UNBLENDED_COST'], group_by=['SERVICE'], report_type='csv', file_name='aws_cost_report') | ||
|
||
# Set a cost alert | ||
monitor.set_cost_alert(start='2023-01-01', end='2023-01-31', threshold=1000.0, email='[email protected]') | ||
``` | ||
|
||
## License | ||
|
||
This package is licensed under the MIT License. See the [LICENSE](LICENSE) file for more information. | ||
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details. | ||
|
||
## Author | ||
|
||
Ahmed Belhaj - [GitHub](https://github.com/Theemiss) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -92,7 +92,7 @@ def get_cost_per_service(self, start: str, end: str, linked_account: str = None) | |
'Start': start, | ||
'End': end | ||
}, | ||
Granularity='DAILY', | ||
Granularity='MONTHLY', | ||
Metrics=['UNBLENDED_COST'], | ||
GroupBy=group_by | ||
) | ||
|
@@ -122,3 +122,140 @@ def get_cost_per_service_graph(self, start: str, end: str, linked_account: str = | |
plt.tight_layout() | ||
|
||
plt.show() | ||
|
||
def generate_report(self, start: str, end: str, report_type: str = 'csv', file_name: str = 'aws_cost_report') -> None: | ||
""" | ||
Generates a customizable report of AWS costs. | ||
:param start: Start date in 'YYYY-MM-DD' format. | ||
:param end: End date in 'YYYY-MM-DD' format. | ||
:param granularity: Granularity of the data (DAILY, MONTHLY). | ||
:param metrics: List of metrics to fetch (e.g., ['UNBLENDED_COST']). | ||
:param group_by: List of dimensions to group by. | ||
:param report_type: Type of the report to generate ('csv' or 'json'). | ||
:param file_name: Name of the report file. | ||
""" | ||
group_by = [] | ||
group_by = ["LINKED_ACCOUNT"] + group_by | ||
response = self.client.get_cost_and_usage( | ||
TimePeriod={ | ||
'Start': start, | ||
'End': end | ||
}, | ||
Granularity="MONTHLY", | ||
Metrics=['UNBLENDED_COST'], | ||
GroupBy=[{'Type': 'DIMENSION', 'Key': item} for item in group_by] | ||
) | ||
|
||
if report_type == 'csv': | ||
self._generate_csv_report(response, file_name) | ||
elif report_type == 'json': | ||
self._generate_json_report(response, file_name) | ||
else: | ||
raise ValueError("Unsupported report type. Use 'csv' or 'json'.") | ||
|
||
def _generate_csv_report(self, data: dict, file_name: str) -> None: | ||
import csv | ||
with open(f'{file_name}.csv', 'w', newline='') as csvfile: | ||
writer = csv.writer(csvfile) | ||
writer.writerow(["TimePeriod", "Group", "Amount", "Unit"]) | ||
for result in data['ResultsByTime']: | ||
time_period = f"{result['TimePeriod']['Start']} - {result['TimePeriod']['End']}" | ||
for group in result['Groups']: | ||
group_name = ', '.join(group['Keys']) | ||
amount = group['Metrics']['UnblendedCost']['Amount'] | ||
unit = group['Metrics']['UnblendedCost']['Unit'] | ||
writer.writerow([time_period, group_name, amount, unit]) | ||
|
||
def _generate_json_report(self, data: dict, file_name: str) -> None: | ||
import json | ||
with open(f'{file_name}.json', 'w') as jsonfile: | ||
json.dump(data, jsonfile, indent=4) | ||
|
||
def get_cost_per_region(self, start: str, end: str) -> dict: | ||
response = self.client.get_cost_and_usage( | ||
TimePeriod={ | ||
'Start': start, | ||
'End': end | ||
}, | ||
Granularity='MONTHLY', | ||
Metrics=['UNBLENDED_COST'], | ||
GroupBy=[{'Type': 'DIMENSION', 'Key': 'REGION'}] | ||
) | ||
|
||
region_cost = {} | ||
for group in response['ResultsByTime'][0]['Groups']: | ||
region_name = group['Keys'][0] | ||
cost = group['Metrics']['UnblendedCost']['Amount'] | ||
region_cost[region_name] = cost | ||
return region_cost | ||
|
||
def get_cost_per_region_graph(self, start: str, end: str): | ||
import matplotlib.pyplot as plt | ||
region_cost = self.get_cost_per_region(start, end) | ||
regions = list(region_cost.keys()) | ||
costs = list(region_cost.values()) | ||
sorted_region_cost = sorted(zip(costs, regions), reverse=False) | ||
sorted_costs, sorted_regions = zip(*sorted_region_cost) | ||
fig, ax = plt.subplots() | ||
ax.bar(sorted_regions, sorted_costs) | ||
ax.set_xlabel('Regions') | ||
ax.set_ylabel('Cost (USD)') | ||
ax.set_title(f'Cost per Region From {start} to {end}') | ||
|
||
plt.xticks(rotation=45) | ||
plt.tight_layout() | ||
|
||
plt.show() | ||
|
||
def set_cost_alert(self, start: str, end: str, threshold: float, email: str, granularity: str = 'MONTHLY'): | ||
""" | ||
Sets an alert for AWS costs. | ||
:param start: Start date in 'YYYY-MM-DD' format. | ||
:param end: End date in 'YYYY-MM-DD' format. | ||
:param threshold: Cost threshold for the alert. | ||
:param email: Email address to send the alert. | ||
:param granularity: Granularity of the data (DAILY, MONTHLY). | ||
""" | ||
total_cost = self.get_total_cost(start, end, granularity) | ||
if total_cost > threshold: | ||
self.send_alert_email(email, total_cost, threshold) | ||
|
||
def get_total_cost(self, start: str, end: str, granularity: str = 'MONTHLY') -> float: | ||
response = self.client.get_cost_and_usage( | ||
TimePeriod={ | ||
'Start': start, | ||
'End': end | ||
}, | ||
Granularity=granularity, | ||
Metrics=['UNBLENDED_COST'] | ||
) | ||
total_cost = sum(float(result['Total']['UnblendedCost']['Amount']) | ||
for result in response['ResultsByTime']) | ||
return total_cost | ||
|
||
def send_alert_email(self, email: str, total_cost: float, threshold: float): | ||
sender_email = "[email protected]" | ||
sender_password = "your_email_password" | ||
subject = "AWS Cost Alert" | ||
body = f"Alert: Your AWS cost has exceeded the threshold.\n\nTotal Cost: ${total_cost}\nThreshold: ${threshold}" | ||
import smtplib | ||
from email.mime.text import MIMEText | ||
from email.mime.multipart import MIMEMultipart | ||
msg = MIMEMultipart() | ||
msg['From'] = sender_email | ||
msg['To'] = email | ||
msg['Subject'] = subject | ||
msg.attach(MIMEText(body, 'plain')) | ||
|
||
try: | ||
server = smtplib.SMTP('smtp.example.com', 587) | ||
server.starttls() | ||
server.login(sender_email, sender_password) | ||
text = msg.as_string() | ||
server.sendmail(sender_email, email, text) | ||
server.quit() | ||
print(f"Alert email sent to {email}") | ||
except Exception as e: | ||
print(f"Failed to send alert email: {e}") |