-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMocren.py
executable file
·158 lines (114 loc) · 6.26 KB
/
Mocren.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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#!/usr/bin/env python3
import argparse
import datetime
import json
import pathlib
import requests
import shutil
import sys
from MocrenConfig import MENTION_TO, WEBHOOK_URL
from MocrenTestSites import test_sites
# 前回のデータを保存する JSON のパス
JSON_PATH = pathlib.Path(sys.argv[0]).parent / 'Mocren.json'
# バージョン情報
VERSION = '1.0.0'
# Discord に通知を投げる関数
def SendDiscord(message: str):
requests.post(WEBHOOK_URL, json={
'username': 'Mocren',
'content': (f'<@{MENTION_TO}> ' if MENTION_TO is not None else '') + message, # メンション先を設定
})
def main():
# ターミナルの横幅
# conhost.exe だと -1px しないと改行されてしまう
terminal_columns = shutil.get_terminal_size().columns - 1
# 引数解析
parser = argparse.ArgumentParser(
description='Mocren: Monitor Cross-site and Report Errors via Network',
formatter_class=argparse.RawTextHelpFormatter,
)
parser.add_argument('-v', '--version', action='version', help='バージョン情報を表示する', version='Mocren version ' + VERSION)
parser.parse_args()
print('=' * terminal_columns)
print('----- Mocren: Monitor Cross-site and Report Errors via Network ----')
print('=' * terminal_columns)
# まだ JSON がなければ初期値を設定
if JSON_PATH.exists() is False:
initial_save_data = {'LastUpdatedAt': datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S')}
for test_site in test_sites:
initial_save_data[test_site['name']] = True # 初期値は True (テスト成功)
with open(JSON_PATH, mode='w', encoding='utf-8') as fp:
json.dump(initial_save_data, fp, ensure_ascii=False, indent=4)
# 今回 JSON に保存するデータが入る辞書
with open(JSON_PATH, mode='r', encoding='utf-8') as fp:
save_data = json.load(fp)
# 前回の更新時刻
print(f'Last Updated Time : {save_data["LastUpdatedAt"]}')
print(f'Current Time : {datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")}')
for test_site in test_sites:
# ---------- テスト開始 ----------
print('-' * terminal_columns)
# テスト対象のサイトにリクエスト
## リダイレクトはフォローしない
## タイムアウトは 20 秒
try:
response = requests.get(test_site['url'], headers={'User-Agent': f'Mocren/{VERSION}'}, allow_redirects=False, timeout=20)
response.encoding = 'utf-8'
# 接続がタイムアウトになった
except requests.exceptions.Timeout:
# 前回のテストが正常だった場合のみ通知
if save_data[test_site['name']] is True:
SendDiscord(f'**{test_site["name"]}** で ⚠**Timeout Error**⚠ が発生しています。\n(URL: {test_site["url"]})')
print(f'{test_site["name"]}: ❌ Timeout Error')
save_data[test_site['name']] = False
continue
# 接続がエラーになった
except requests.exceptions.ConnectionError:
# 前回のテストが正常だった場合のみ通知
if save_data[test_site['name']] is True:
SendDiscord(f'**{test_site["name"]}** で ⚠**Connection Error**⚠ が発生しています。\n(URL: {test_site["url"]})')
print(f'{test_site["name"]}: ❌ Connection Error')
save_data[test_site['name']] = False
continue
# テスト対象のサイトのステータスコードが正常時と一致しない
if response.status_code != test_site['normal_status_code']:
# 前回のテストが正常だった場合のみ通知
if save_data[test_site['name']] is True:
error_message = f'**{test_site["name"]}** で ⚠**HTTP Error {response.status_code}**⚠ が発生しています。\n(URL: {test_site["url"]})'
# HTTP 30x の場合はリダイレクト先も通知
if 300 <= response.status_code < 400 and 'Location' in response.headers:
error_message += f'\nRedirect to: {response.headers["Location"]}'
SendDiscord(error_message)
status_message = f'{test_site["name"]}: ❌ HTTP Error {response.status_code} (HTTP Status {test_site["normal_status_code"]} was expected)'
# HTTP 30x の場合はリダイレクト先も表示
if 300 <= response.status_code < 400 and 'Location' in response.headers:
status_message += f'\n Redirect to: {response.headers["Location"]}'
print(status_message)
save_data[test_site['name']] = False
continue
# テスト対象のサイトのレスポンスが正常時のレスポンスデータの一部と一致しない
if test_site['normal_response_data'] not in response.text:
# 前回のテストが正常だった場合のみ通知
if save_data[test_site['name']] is True:
SendDiscord(f'**{test_site["name"]}** で ⚠**Response Data Error**⚠ が発生しています。\n(URL: {test_site["url"]})')
print(f'{test_site["name"]}: ❌ Response Data Error (HTTP Status {response.status_code}))')
save_data[test_site['name']] = False
continue
# ---------- テスト終了 ----------
# ここまでのテストに通過していれば、成功している
## 前回のテストが失敗だった場合のみ通知
if save_data[test_site['name']] is False:
SendDiscord(f'**{test_site["name"]} **が 🎉**復旧**🎊 しました!\n(URL: {test_site["url"]})')
save_data[test_site['name']] = True
print(f'{test_site["name"]}: ✅ Success (HTTP Status {response.status_code})')
# ---------- 後処理 ----------
print('-' * terminal_columns)
# 前回の更新時刻を更新
save_data['LastUpdatedAt'] = datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S')
# 次回実行時用にデータを保存しておく
with open(JSON_PATH, mode='w', encoding='utf-8') as fp:
json.dump(save_data, fp, ensure_ascii=False, indent=4)
print('Completed.')
print('=' * terminal_columns)
if __name__ == '__main__':
main()