在公司裡做的一個接口系統,主要是對接第三方的系統接口,是以,這個系統裡會和很多其他公司的項目互動。随之而來一個很蛋疼的問題,這麼多公司的接口,不同公司接口的穩定性差别很大,通路量大的時候,有的不怎麼行的接口就各種出錯了。
這個接口系統剛剛開發不久,整個系統中,處于比較邊緣的位置,不像其他項目,有日志庫,還有短信告警,一旦出問題,很多情況下都是使用者回報回來,是以,我的想法是,拿起python,為這個項目寫一個監控。如果在調用某個第三方接口的過程中,大量出錯了,說明這個接口有有問題了,就可以更快的采取措施。
項目的也是有日志庫的,所有的info,error日志都是每隔一分鐘掃描入庫,日志庫是用的mysql,表裡有幾個特别重要的字段:
level 日志級别
message 日志内容
file_name java代碼檔案
log_time 日志時間
有日志庫,就不用自己去線上環境掃日志分析了,直接從日志庫入手。由于日志庫線上上時每隔1分鐘掃,那我就去日志庫每隔2分鐘掃一次,如果掃到有一定數量的error日志就報警,如果隻有一兩條錯誤就可以無視了,也就是短時間爆發大量錯誤日志,就可以斷定系統有問題了。報警方式就用發送郵件,是以,需要做下面幾件事情:
1. 操作mysql。
2. 發送郵件。
3. 定時任務。
4. 日志。
5. 運作腳本。
明确了以上幾件事情,就可以動手了。
操作資料庫
使用mysqldb這個驅動,直接操作資料庫,主要就是查詢操作。
擷取資料庫的連接配接:
?
<col>
1
2
3
4
5
6
7
8
<code>def</code> <code>get_con():</code>
<code>host </code><code>=</code> <code>"127.0.0.1"</code>
<code>port </code><code>=</code> <code>3306</code>
<code>logsdb </code><code>=</code> <code>"logsdb"</code>
<code>user </code><code>=</code> <code>"root"</code>
<code>password </code><code>=</code> <code>"never tell you"</code>
<code>con </code><code>=</code> <code>mysqldb.connect(host</code><code>=</code><code>host, user</code><code>=</code><code>user, passwd</code><code>=</code><code>password, db</code><code>=</code><code>logsdb, port</code><code>=</code><code>port, charset</code><code>=</code><code>"utf8"</code><code>)</code>
<code>return</code> <code>con</code>
從日志庫裡擷取資料,擷取目前時間之前2分鐘的資料,首先,根據目前時間進行計算一下時間。之前,計算有問題,現在已經修改。
<code>def</code> <code>calculate_time():</code>
<code>now </code><code>=</code> <code>time.mktime(datetime.now().timetuple())</code><code>-</code><code>60</code><code>*</code><code>2</code>
<code>result </code><code>=</code> <code>time.strftime(</code><code>'%y-%m-%d %h:%m:%s'</code><code>, time.localtime(now))</code>
<code>return</code> <code>result</code>
然後,根據時間和日志級别去日志庫查詢資料
9
10
11
12
13
14
15
16
17
<code>def</code> <code>get_data():</code>
<code>select_time </code><code>=</code> <code>calculate_time()</code>
<code>logger.info(</code><code>"select time:"</code><code>+</code><code>select_time)</code>
<code>sql </code><code>=</code> <code>"select file_name,message from logsdb.app_logs_record "</code> <code>\</code>
<code>"where log_time >"</code><code>+</code><code>"'"+select_time+"'"</code> <code>\</code>
<code>"and level="</code><code>+</code><code>"'error'"</code> <code>\</code>
<code>"order by log_time desc"</code>
<code>conn </code><code>=</code> <code>get_con()</code>
<code>cursor </code><code>=</code> <code>conn.cursor()</code>
<code>cursor.execute(sql)</code>
<code>results </code><code>=</code> <code>cursor.fetchall()</code>
<code>cursor.close()</code>
<code>conn.close()</code>
<code>return</code> <code>results</code>
發送郵件
使用python發送郵件比較簡單,使用标準庫smtplib就可以
這裡使用163郵箱進行發送,你可以使用其他郵箱或者企業郵箱都行,不過host和port要設定正确。
18
<code>def</code> <code>send_email(content):</code>
<code>sender </code><code>=</code> <code>"[email protected]"</code>
<code>receiver </code><code>=</code> <code>[</code><code>"[email protected]"</code><code>, </code><code>"[email protected]"</code><code>]</code>
<code>host </code><code>=</code> <code>'smtp.163.com'</code>
<code>port </code><code>=</code> <code>465</code>
<code>msg </code><code>=</code> <code>mimetext(content)</code>
<code>msg[</code><code>'from'</code><code>] </code><code>=</code> <code>"[email protected]"</code>
<code>msg[</code><code>'to'</code><code>] </code><code>=</code> <code>"[email protected],[email protected]"</code>
<code>msg[</code><code>'subject'</code><code>] </code><code>=</code> <code>"system error warning"</code>
<code>try</code><code>:</code>
<code>smtp </code><code>=</code> <code>smtplib.smtp_ssl(host, port)</code>
<code>smtp.login(sender, </code><code>'123456'</code><code>)</code>
<code>smtp.sendmail(sender, receiver, msg.as_string())</code>
<code>logger.info(</code><code>"send email success"</code><code>)</code>
<code>except</code> <code>exception, e:</code>
<code>logger.error(e)</code>
定時任務
使用一個單獨的線程,每2分鐘掃描一次,如果error級别的日志條數超過5條,就發郵件通知。
<code>def</code> <code>task():</code>
<code>while</code> <code>true</code><code>:</code>
<code>logger.info(</code><code>"monitor running"</code><code>)</code>
<code>results </code><code>=</code> <code>get_data()</code>
<code>if</code> <code>results </code><code>is</code> <code>not</code> <code>none</code> <code>and</code> <code>len</code><code>(results) > </code><code>5</code><code>:</code>
<code>content </code><code>=</code> <code>"recharge error:"</code>
<code>logger.info(</code><code>"a lot of error,so send mail"</code><code>)</code>
<code>for</code> <code>r </code><code>in</code> <code>results:</code>
<code>content </code><code>+</code><code>=</code> <code>r[</code><code>1</code><code>]</code><code>+</code><code>'\n'</code>
<code>send_email(content)</code>
<code>sleep(</code><code>2</code><code>*</code><code>60</code><code>)</code>
日志
為這個小小的腳本配置一下日志log.py,讓日志可以輸出到檔案和控制台中。
<code># coding=utf-8</code>
<code>import</code> <code>logging</code>
<code>logger </code><code>=</code> <code>logging.getlogger(</code><code>'mylogger'</code><code>)</code>
<code>logger.setlevel(logging.debug)</code>
<code>fh </code><code>=</code> <code>logging.filehandler(</code><code>'monitor.log'</code><code>)</code>
<code>fh.setlevel(logging.info)</code>
<code>ch </code><code>=</code> <code>logging.streamhandler()</code>
<code>ch.setlevel(logging.info)</code>
<code>formatter </code><code>=</code> <code>logging.formatter(</code><code>'%(asctime)s - %(name)s - %(levelname)s - %(message)s'</code><code>)</code>
<code>fh.setformatter(formatter)</code>
<code>ch.setformatter(formatter)</code>
<code>logger.addhandler(fh)</code>
<code>logger.addhandler(ch)</code>
是以,最後,這個監控小程式就是這樣的app_monitor.py
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
<code>import</code> <code>threading</code>
<code>import</code> <code>mysqldb</code>
<code>from</code> <code>datetime </code><code>import</code> <code>datetime</code>
<code>import</code> <code>time</code>
<code>import</code> <code>smtplib</code>
<code>from</code> <code>email.mime.text </code><code>import</code> <code>mimetext</code>
<code>from</code> <code>log </code><code>import</code> <code>logger</code>
<code>time.sleep(</code><code>2</code><code>*</code><code>60</code><code>)</code>
<code>def</code> <code>run_monitor():</code>
<code>monitor </code><code>=</code> <code>threading.thread(target</code><code>=</code><code>task)</code>
<code>monitor.start()</code>
<code>if</code> <code>__name__ </code><code>=</code><code>=</code> <code>"__main__"</code><code>:</code>
<code>run_monitor()</code>
運作腳本
腳本在伺服器上運作,使用supervisor進行管理。
在伺服器(centos6)上安裝supervisor,然後在/etc/supervisor.conf中加入一下配置:
複制代碼代碼如下:
[program:app-monitor]
command = python /root/monitor/app_monitor.py
directory = /root/monitor
user = root
然後在終端中運作supervisord啟動supervisor。
在終端中運作supervisorctl,進入shell,運作status檢視腳本的運作狀态。
總結
這個小監控思路很清晰,還可以繼續修改,比如:監控特定的接口,發送短信通知等等。
因為有日志庫,就少了去線上正式環境掃描日志的麻煩,是以,如果沒有日志庫,就要自己上線上環境掃描,在正式線上環境一定要小心哇~