Forked from themartorana/fastlyMonthToDateBill.py
Last active
January 18, 2023 20:53
-
-
Save achton/bba8fe65af1e3f86b2fc7f4603d0cf8f to your computer and use it in GitHub Desktop.
Calculate your month-to-date bill from Fastly with the billing API
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
#!/usr/bin/env python3 | |
# Requires Python 3 | |
import requests | |
import locale | |
from typing import Dict, Tuple, List | |
from calendar import monthrange | |
from datetime import datetime | |
FASTLY_URL = "https://api.fastly.com/stats/usage_by_month?billable_units=true" | |
FASTLY_API_KEY = "<YOUR-API-KEY-HERE>" | |
FASTLY_ZONES = { | |
"anzac": "Australia & New Zealand", | |
"asia": "Asia", | |
"asia_india": "India", | |
"europe": "Europe", | |
"latam": "Brazil", | |
"south_africa": "South Africa", | |
"southamerica_std": "South America", | |
"usa": "North America" | |
} | |
FASTLY_PRICING = { | |
"anzac": { | |
"gig_low": 0.19, | |
"gig_high": 0.14, | |
"req": 0.009 | |
}, | |
"asia": { | |
"gig_low": 0.19, | |
"gig_high": 0.14, | |
"req": 0.009 | |
}, | |
"asia_india": { | |
"gig_low": 0.28, | |
"gig_high": 0.24, | |
"req": 0.016 | |
}, | |
"europe": { | |
"gig_low": 0.12, | |
"gig_high": 0.08, | |
"req": 0.0075 | |
}, | |
"latam": { | |
"gig_low": 0.28, | |
"gig_high": 0.24, | |
"req": 0.016 | |
}, | |
"south_africa": { | |
"gig_low": 0.28, | |
"gig_high": 0.24, | |
"req": 0.016 | |
}, | |
"southamerica_std": { | |
"gig_low": 0.19, | |
"gig_high": 0.14, | |
"req": 0.009 | |
}, | |
"usa": { | |
"gig_low": 0.12, | |
"gig_high": 0.08, | |
"req": 0.0075 | |
} | |
} | |
def ascurrency(amount: float) -> str: | |
return locale.currency( | |
amount, | |
"$", | |
grouping=True | |
) | |
def grab() -> Dict: | |
r = requests.get( | |
FASTLY_URL, | |
headers = { | |
"Fastly-Key": FASTLY_API_KEY, | |
} | |
) | |
if r.status_code != 200: | |
raise Exception("Received %d, was expecting 200" % r.status_code) | |
# Response is json | |
jpacket = r.json() | |
if jpacket["status"] != "success": | |
raise Exception("Status is not success: %s" % jpacket["status"]) | |
return jpacket | |
def calc_service(service: Dict) -> None: | |
# Just look at the production avatar cache | |
treq = 0.0 | |
tbw = 0.0 | |
tc = 0.0 | |
for region, v in service.items(): | |
if region == "name": | |
continue | |
# Get the matching region costs | |
regcost = FASTLY_PRICING[region] | |
# Numbers | |
bw = v["bandwidth"] | |
tbw += bw | |
req = v["requests"] | |
treq += req | |
# Calculations | |
creq = req * regcost["req"] | |
cbw = 0.0 | |
if bw < 1: | |
cbw = bw * regcost["gig_low"] | |
else: | |
clow = regcost["gig_low"] | |
chigh = (bw - 1) * regcost["gig_high"] | |
cbw = clow + chigh | |
tc += cbw + creq | |
print("""%s | |
bw: %s (%.4f GB * %.2f/%.2f/GB) | |
requests: %s (%s * %f/10k) | |
------ | |
total: %s""" % ( | |
FASTLY_ZONES[region].upper(), | |
# BW | |
ascurrency(cbw), | |
bw, | |
regcost["gig_low"], | |
regcost["gig_high"], | |
# Requests | |
locale.currency( | |
creq, | |
"$", | |
grouping=True | |
), | |
locale.format_string( | |
"%.2d", | |
req * 10000, | |
grouping=True | |
), | |
regcost["req"], | |
# Total | |
locale.currency( | |
creq + cbw, | |
"$", | |
grouping=True | |
), | |
)) | |
return tc | |
def grab_and_calc() -> None: | |
jpacket = grab() | |
services = jpacket["data"]["services"] | |
print("There are %d services" % len(services.keys())) | |
ts = 0.0 | |
for k, v in services.items(): | |
print("\n%s\n=========================" % v["name"]) | |
tsc = calc_service(v) | |
ts += tsc | |
print( | |
"\nTotal \'%s\' Cost: %s" % ( | |
v["name"], | |
locale.currency( | |
tsc, | |
"$", | |
grouping=True | |
) | |
) | |
) | |
print( | |
"\nMONTH SPEND TO DATE: %s" % ( | |
ascurrency(ts) | |
) | |
) | |
# Extract for month | |
today = datetime.today() | |
day_in_month = today.day | |
days_in_month = monthrange(today.year, today.month)[1] | |
tspace = ts/(day_in_month/days_in_month) | |
print( | |
"MONTH TOTAL SPEND PACE: %s" % ( | |
ascurrency(tspace) | |
) | |
) | |
print( | |
"\033[3mBased on %d/%d days in month\033[0m" % ( | |
day_in_month, | |
days_in_month | |
) | |
) | |
if __name__ == "__main__": | |
locale.setlocale(locale.LC_ALL, 'en_US.utf8') | |
grab_and_calc() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment