Skip to content

Commit

Permalink
aws monitor v1
Browse files Browse the repository at this point in the history
  • Loading branch information
Theemiss committed Jul 13, 2024
1 parent 6eefb13 commit 3ff6fdc
Show file tree
Hide file tree
Showing 2 changed files with 216 additions and 15 deletions.
92 changes: 78 additions & 14 deletions README.md
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

Expand Down Expand Up @@ -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)
139 changes: 138 additions & 1 deletion aws_monitoring/org/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Expand Down Expand Up @@ -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}")

0 comments on commit 3ff6fdc

Please sign in to comment.