-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathping_async.py
137 lines (116 loc) · 5.33 KB
/
ping_async.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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import requests
import asyncio
from concurrent.futures import ThreadPoolExecutor
import datetime
import configparser
import json
import os
import sys
import logging
import smtplib
from requests.exceptions import ConnectionError
def json_output(data):
"""Helper function for outputting json file that contains site state after check"""
with open(os.path.dirname(sys.argv[0]) + "/" + 'sites_state.json', 'w') as outfile:
json.dump(data, outfile)
def json_read():
"""Helper function for reading json file with previous state of web-sites"""
try:
with open(os.path.dirname(sys.argv[0]) + "/" + 'sites_state.json') as json_file:
data = json.load(json_file)
return data
except FileNotFoundError:
return None
async def send_email(config, site, status_code, time, back=False):
"""Helper function for sending emails"""
recipients = json.loads(config['RECIPIENTS']['EMAILS'])
smtp_server = config['EMAIL']['SMTP_SERVER']
port = config['EMAIL']['PORT']
from_email = config['EMAIL']['FROM_EMAIL']
password = config['EMAIL']['PASSWORD']
logging.basicConfig(filename=config['LOG']['EMAIL'], level=logging.WARN)
try:
server = smtplib.SMTP_SSL(smtp_server, port)
server.ehlo() # Can be omitted
server.login(from_email, password)
for recipient in recipients:
message = "\r\n".join([
"From: {}".format(from_email),
"To: {}".format(recipient),
"Subject: {} {}".format(site, 'BACK ONLINE' if back else 'IS DOWN'),
"",
'Resource {} \nresponded with {} at {}'.format(site, status_code, time)
])
if back:
message += "\nResource is BACK ONLINE!"
server.sendmail(from_email, recipient, message)
except Exception as e:
logging.error(' {} — {}'.format(time, e))
finally:
server.quit()
def fetch(session, site):
try:
with session.get(site, headers={'User-Agent': 'Mozilla/5.0'}) as response:
return {site: response.status_code}
except Exception as err:
return {site: err}
async def ping_async(cfg):
# initialization
if len(cfg) > 1:
cfg = cfg[1]
else:
# if no files were passed in command line, run with default 'config.ini'
cfg = os.path.dirname(sys.argv[0]) + "/" + 'config.ini'
config = configparser.ConfigParser()
config.read(cfg)
sites = json.loads(config['SITES']['SITES'])
data = json_read()
sites_state = {}
with ThreadPoolExecutor(max_workers=15) as executor:
with requests.Session() as session:
# Set any session parameters here before calling `fetch`
loop = asyncio.get_event_loop()
tasks = [
loop.run_in_executor(
executor,
fetch,
*(session, site) # Allows us to pass in multiple arguments to `fetch`
)
for site in sites
]
responses = await asyncio.gather(*tasks)
for i in range(len(responses)):
for site in responses[i]:
current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
if data:
# if resource was DOWN but now it's UP
if responses[i][site] == 200 and data.get(site, 404) != 200:
logging.error(' {} — !!! {} !!! BACK ONLINE — {}'.format(current_time, site, responses[i][site]))
sites_state[site] = 200
await send_email(config, site, responses[i][site], current_time, back=True)
# if site is DOWN for a 2nd check in a row
elif responses[i][site] != 200 and data.get(site, 404) != 200:
logging.error(' {} — !!! {} !!! — {}'.format(current_time, site, responses[i][site]))
sites_state[site] = 404 if isinstance(responses[i][site], ConnectionError) else responses[i][site]
# basic case when the web site was UP on previous checks but now it's DOWN
if responses[i][site] != 200 and (not data or data.get(site, 404) == 200):
logging.error(' {} — !!! {} !!! — {}'.format(current_time, site, responses[i][site]))
sites_state[site] = 404 if isinstance(responses[i][site], ConnectionError) else responses[i][site]
await send_email(config, site, responses[i][site], current_time)
# site was UP and it's still UP
else:
logging.warning(' {} — !!! {} !!! — {}'.format(current_time, site, responses[i][site]))
sites_state[site] = 404 if isinstance(responses[i][site], ConnectionError) else responses[i][site]
sites_state['LAST_CHECK'] = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
print(sites_state)
json_output(sites_state)
def main(cfg):
loop = asyncio.get_event_loop()
future = asyncio.ensure_future(ping_async(cfg))
loop.run_until_complete(future)
if __name__ == "__main__":
from time import time
start = time()
main(sys.argv)
end = time()
print('Elapsed time: {}'.format(end - start))