Skip to content

Commit

Permalink
Merge pull request #1 from Theemiss/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
Theemiss authored Jul 13, 2024
2 parents 0bd1fc3 + 5678f6c commit 6eefb13
Show file tree
Hide file tree
Showing 9 changed files with 314 additions and 48 deletions.
19 changes: 19 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Copyright (c) 2024 The Python Packaging Authority

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
119 changes: 110 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,115 @@
# aws-monitor
# AWS Cost Monitoring Package

A python package for monitoring AWS resources.

## Features

- Monitor AWS Cost By Period & Service, Linked Account
- onitor AWS Cost to monitor Service by Linked Account
- Graphs
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.

## Installation

To install the package, use pip:

```bash
pip install aws-monitor==0.4
pip install aws-monitor
```

This will also install the following dependencies:

- `boto3`
- `matplotlib`

## Usage

### AWSOrgMonitor Class

This class inherits from `AWSCostMonitor` and provides methods to fetch and analyze AWS cost data.

#### Initialization

```python
from aws_monitoring.utils import AWSCostMonitor

class AWSOrgMonitor(AWSCostMonitor):
def __init__(self):
super().__init__()
```

#### Get Cost

Fetches the cost data within the specified time period and granularity.

```python
def get_cost(self, start: str, end: str, granularity: str, metrics: list, group_by: list = [], json=False) -> dict:
```

- **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.
- **json**: Whether to return the response in JSON format.

#### Get Billed Accounts

Fetches the list of billed accounts within the specified time period.

```python
def get_billed_accounts(self, start: str, end: str) -> dict:
```

#### Get Cost Per Account

Fetches the cost per account within the specified time period.

```python
def get_cost_per_account(self, start, end) -> dict:
```

#### Get Cost Per Account Graph

Displays a bar graph of the cost per account within the specified time period.

```python
def get_cost_per_account_graph(self, start, end):
```

#### Get Cost Per Service

Fetches the cost per AWS service within the specified time period and optionally for a specific linked account.

```python
def get_cost_per_service(self, start: str, end: str, linked_account: str = None) -> dict:
```

#### Get Cost Per Service Graph

Displays a bar graph of the cost per AWS service within the specified time period and optionally for a specific linked account.

```python
def get_cost_per_service_graph(self, start: str, end: str, linked_account: str = None):
```

### Example Usage

```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)

# Visualize cost per service
monitor.get_cost_per_service_graph(start_date, end_date)

# Get cost per account
account_costs = monitor.get_cost_per_account(start_date, end_date)
print(account_costs)

# Visualize cost per account
monitor.get_cost_per_account_graph(start_date, end_date)
```

## License

This package is licensed under the MIT License. See the [LICENSE](LICENSE) file for more information.
Empty file added aws-monitor.toml
Empty file.
24 changes: 2 additions & 22 deletions aws_monitoring/__init__.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,2 @@
import boto3
from datetime import datetime, timedelta
from aws_monitoring.config import AWSConfig


class AWSCostMonitor():
def __init__(self, config: AWSConfig = AWSConfig()) -> None:
self.client = boto3.client(
'ce', region_name=config.DEFAULT_REGIONS[0], aws_access_key_id=config.AWS_ACCESS_KEY_ID, aws_secret_access_key=config.AWS_SECRET_ACCESS_KEY)

def get_cost_and_usage(self, start: str, end: str, granularity: str, metrics: list, group_by: list) -> dict:
response = self.client.get_cost_and_usage(
TimePeriod={
'Start': start,
'End': end
},
Granularity=granularity,
Metrics=metrics,
GroupBy=[{'Type': 'COST_CATEGORY', 'Key': item}
for item in group_by]
)
return response
from aws_monitoring.utils import AWSCostMonitor
from aws_monitoring.org import AWSOrgMonitor
1 change: 1 addition & 0 deletions aws_monitoring/org/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from aws_monitoring.org.utils import AWSOrgMonitor
124 changes: 124 additions & 0 deletions aws_monitoring/org/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@

from aws_monitoring.utils import AWSCostMonitor


class AWSOrgMonitor(AWSCostMonitor):
def __init__(self):
super().__init__()

def get_cost(self, start: str, end: str, granularity: str, metrics: list, group_by: list = [], json=False) -> dict:
group_by = ["LINKED_ACCOUNT"] + group_by
response = self.client.get_cost_and_usage(
TimePeriod={
'Start': start,
'End': end
},
Granularity=granularity,
Metrics=metrics,
GroupBy=[{'Type': 'COST_CATEGORY', 'Key': item}
for item in group_by]
)
if json:
return self.to_json(response)
return response

def get_billed_accounts(self, start: str, end: str) -> dict:
response = self.client.get_dimension_values(
TimePeriod={
'Start': start,
'End': end
},
Dimension='LINKED_ACCOUNT',
Context='COST_AND_USAGE',
SearchString="*"
)
users = [{"id": item['Value'], "name": item['Attributes']
['description']} for item in response['DimensionValues']]

return users

def get_cost_per_account(self, start, end) -> dict:
billed_accounts = self.get_billed_accounts(start, end)
response = self.client.get_cost_and_usage(
TimePeriod={
'Start': start,
'End': end
},
Granularity='MONTHLY',
Metrics=['UNBLENDED_COST'],
GroupBy=[
{'Type': 'DIMENSION', 'Key': 'LINKED_ACCOUNT'}
]
)

accounts_cost = {}
for group in response['ResultsByTime'][0]['Groups']:
account_id = group['Keys'][0]
cost = group['Metrics']['UnblendedCost']['Amount']
account_name = next(
(account['name'] for account in billed_accounts if account['id'] == account_id), account_id)
accounts_cost[account_name] = cost

return accounts_cost

def get_cost_per_account_graph(self, start, end):
import matplotlib.pyplot as plt

accounts_cost = self.get_cost_per_account(start, end)
accounts = list(accounts_cost.keys())
costs = list(accounts_cost.values())
sorted_accounts_cost = sorted(zip(costs, accounts), reverse=False)
sorted_costs, sorted_accounts = zip(*sorted_accounts_cost)

fig, ax = plt.subplots()
ax.bar(sorted_accounts, sorted_costs)
ax.set_xlabel('Accounts')
ax.set_ylabel('Cost (USD)')
ax.set_title(f'Cost per Account From {start} to {end}')

# Rotate the x-axis labels for better readability
plt.xticks(rotation=45)
plt.tight_layout()

return plt.show()

def get_cost_per_service(self, start: str, end: str, linked_account: str = None) -> dict:
group_by = [{'Type': 'DIMENSION', 'Key': 'SERVICE'}]
if linked_account:
group_by.append({'Type': 'DIMENSION', 'Key': 'LINKED_ACCOUNT'})

response = self.client.get_cost_and_usage(
TimePeriod={
'Start': start,
'End': end
},
Granularity='DAILY',
Metrics=['UNBLENDED_COST'],
GroupBy=group_by
)

service_cost = {}
for group in response['ResultsByTime'][0]['Groups']:
service_name = group['Keys'][0]
cost = group['Metrics']['UnblendedCost']['Amount']
service_cost[service_name] = cost
service_cost = {k: v for k, v in service_cost.items() if v != 0}
return service_cost

def get_cost_per_service_graph(self, start: str, end: str, linked_account: str = None):
import matplotlib.pyplot as plt
service_cost = self.get_cost_per_service(start, end, linked_account)
services = list(service_cost.keys())
costs = list(service_cost.values())
sorted_service_cost = sorted(zip(costs, services), reverse=False)
sorted_costs, sorted_services = zip(*sorted_service_cost)
fig, ax = plt.subplots()
ax.bar(sorted_services, sorted_costs)
ax.set_xlabel('Services')
ax.set_ylabel('Cost (USD)')
ax.set_title(f'Cost per Service From {start} to {end}')

plt.xticks(rotation=45)
plt.tight_layout()

plt.show()
46 changes: 46 additions & 0 deletions aws_monitoring/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import boto3
from datetime import datetime, timedelta
from aws_monitoring.config import AWSConfig
import json

class AWSCostMonitor():
def __init__(self, config: AWSConfig = AWSConfig()) -> None:
self.client = boto3.client(
'ce', region_name=config.DEFAULT_REGIONS[0], aws_access_key_id=config.AWS_ACCESS_KEY_ID, aws_secret_access_key=config.AWS_SECRET_ACCESS_KEY)

def get_cost(self, start: str, end: str, granularity: str, metrics: list, group_by: list = []) -> dict:
response = self.client.get_cost_and_usage(
TimePeriod={
'Start': start,
'End': end
},
Granularity=granularity,
Metrics=metrics,
GroupBy=[{'Type': 'COST_CATEGORY', 'Key': item}
for item in group_by]
)

return response

@staticmethod
def to_json(response):
with open('response.json', 'w') as f:
json.dump(response, f, indent=4)
return {
"ResultsByTime": [
{
"TimePeriod": result["TimePeriod"],
"Total": result["Total"],
"Groups": [
{
"Keys": group["Keys"],
"Metrics": {
metric["Key"]: metric["Amount"] for metric in group["Metrics"].values()
}
} for group in result["Groups"]
]
} for result in response["ResultsByTime"]
]
}


1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
packages=find_packages(),
install_requires=[
'boto3',
'matplotlib'
],
entry_points={
'console_scripts': [
Expand Down
28 changes: 11 additions & 17 deletions test.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,21 @@


from aws_monitoring import AWSCostMonitor
import json

from aws_monitoring import AWSCostMonitor, AWSOrgMonitor
import datetime
from datetime import timedelta

cost = AWSCostMonitor()

org_cost = AWSOrgMonitor()

data = cost.get_cost_and_usage(start='2024-01-01', end='2024-06-30',
granularity='MONTHLY', metrics=['BlendedCost'], group_by=[])

print(data)
print('\n\n\n')
# Get The costs for last month
last_month = datetime.datetime.now() - timedelta(days=30)
start_date = last_month.replace(day=1)
end_date = start_date + timedelta(days=32)

# Get the costs for the last 30 days
end_date = datetime.datetime.now()
start_date = end_date - timedelta(days=30)

data = cost.get_cost_and_usage(start=start_date.strftime('%Y-%m-%d'), end=end_date.strftime('%Y-%m-%d'),
granularity='DAILY', metrics=['BlendedCost'], group_by=[])

# Get The costs for last 30 days and group them by service
end_date = datetime.datetime.now()
start_date = end_date - timedelta(days=30)
data = cost.get_cost_and_usage(start=start_date.strftime('%Y-%m-%d'), end=end_date.strftime('%Y-%m-%d'),
granularity='DAILY', metrics=['BlendedCost'], group_by=["Service","Linked account"])
service= org_cost.get_cost_per_service_graph(start=start_date.strftime(
'%Y-%m-%d'), end=end_date.strftime('%Y-%m-%d'))
print(service)

0 comments on commit 6eefb13

Please sign in to comment.