-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.py
121 lines (102 loc) · 3.57 KB
/
index.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import click
from cloudflare import retrieve_data
from perma import get_counts
from datetime import datetime, timedelta
import pygal
from pygal.style import DefaultStyle
from jinja2 import Environment, FileSystemLoader
import humanize
@click.command()
def index():
"""
This program prints the index template for the Perma status page.
"""
data = retrieve_data()['data']
x_labels = days_map("%a %Y-%m-%d")
custom_style = DefaultStyle
custom_style.background = 'transparent'
# generate cloudflare graph
cloudflare = pygal.Line(
disable_xml_declaration=True,
height=250,
width=1100,
x_label_rotation=20,
max_scale=10,
style=custom_style
)
cloudflare.x_labels = x_labels
cloudflare.value_formatter = number_formatter
keys = {'bytes', 'threats', 'uniques', 'pageViews', 'requests'}
cloudflare_data = {k: [] for k in keys}
for d in data['viewer']['zones'][0]['httpRequests1dGroups']:
for key in keys - {'uniques'}:
cloudflare_data[key].append(d['sum'][key])
cloudflare_data['uniques'].append(d['uniq']['uniques'])
for key in keys - {'bytes'}:
cloudflare.add(key,
cloudflare_data[key],
formatter=lambda d: humanize.intcomma(d))
cloudflare.add('bytes',
cloudflare_data['bytes'],
secondary=True,
formatter=lambda d: sizeof_formatter(d))
# generate perma captures graph
captures = pygal.Line(disable_xml_declaration=True,
height=250,
width=1100,
x_label_rotation=20,
style=custom_style)
captures.x_labels = x_labels
captures.value_formatter = number_formatter
days = days_map("%Y-%m-%d")
counts = get_counts(days)
captures.add("captures",
[counts[day] for day in days],
formatter=lambda d: humanize.intcomma(d))
# prepare template
loader = FileSystemLoader('templates')
template = Environment(loader=loader).get_template('base.html')
def edit(chart):
"""
Replace the "Pygal" title, since pygal doesn't allow you to omit it.
"""
return chart.render(show_legend=True, is_unicode=True).replace(
'<title>Pygal</title>',
'<title>Perma captures</title>'
)
renders = list(map(edit, [captures, cloudflare]))
print(template.render(
captures=renders[0],
cloudflare=renders[1]))
def days_map(format):
"""
Helper function for generating a list of day-strings in a given format
"""
today = datetime.today()
return list(map(
lambda d: d.strftime(format),
[today + timedelta(days=i) for i in range(-7, 0)]
))
# adapted from https://stackoverflow.com/a/1094933/4074877
def sizeof_formatter(num, suffix=''):
"""
This formatter is intended for the "bytes" tooltip in the
Cloudflare graph.
"""
for unit in ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']:
if abs(num) < 1024.0:
return f'{num:.1f}{unit}{suffix}'
num /= 1024.0
return f'{num:.1f}Yi{suffix}'
def number_formatter(x):
"""
This formatter is meant to handle both y-axes of the Cloudflare
graph, and is used for the capture graph as well. The mismatch
between its behavior and sizeof_formatter's is "intended".
"""
if x > 2000000:
return f'{round(x / 1024 / 1024)}M'
else:
return f'{humanize.intcomma(round(x))}'
if __name__ == '__main__':
index()