├── README.md
├── Smtp.class.php
├── pt-kill.php
├── pt_kill演示录像.zip
├── simplejson-3.8.2.tar.gz
├── smtp_config.php
└── wechat.py
/README.md:
--------------------------------------------------------------------------------
1 | /**
2 | * Percona PT-kill重构版(PHP)
3 | * https://github.com/hcymysql/pt-kill
4 | *
5 | * UPDATE:
6 | * Modified by: hcymysql 2018/11/27
7 | * 1、增加慢SQL邮件报警功能
8 | * 2、增加慢SQL微信报警功能
9 | *
10 | * 环境准备:
11 | * shell> yum install -y php-process php php-mysql
12 | *
13 | */
14 |
15 | 概述
16 | 原生Percona版 PT-kill(Perl)工具只是单纯的KILL掉正在运行中的慢SQL,而不能作为一个监控工具使用,例如缺少邮件报警或者微信报警功能,固需要将其重构。
17 |
18 | 重构版 PT-kill(PHP)从information_schema.PROCESSLIST表中捕获正在运行中的SELECT|ALTER等DML/DDL消耗资源过多的查询,过滤它们,然后杀死它们(可选择不杀)且发邮件/微信报警给DBA和相关开发知悉,避免因慢SQL执行时间过长对数据库造成一定程度的伤害。
19 |
20 | (注:慢SQL执行完才记录到slow.log里,执行过程中不记录。)
21 |
22 | Usage:
23 |
24 | Options:
25 |
26 | -u username
27 |
28 | -p password
29 |
30 | -h host ip
31 |
32 | -P port
33 |
34 | -B busytime time seconds 设置慢SQL执行时间触发报警
35 |
36 | -I interval time seconds 设置守护进程下间隔监测时间
37 |
38 | --kill 如果想杀掉慢查询,加上该选项。
39 |
40 | --match-info 匹配杀掉SELECT|INSERT|UPDATE语句
41 |
42 | --match-user 匹配杀掉的用户
43 |
44 | --daemon 1开启后台守护进程,0关闭后台守护进程
45 |
46 | --mail 开启发送邮件报警
47 |
48 | --weixin 开启发送微信报警
49 |
50 | --help Help
51 |
52 |
53 | Example :
54 |
55 | 前台运行
56 |
57 | shell> php pt-kill.php -u admin -p 123456 -h 10.10.159.31 -P 3306 -B 10 --match-info='select|alter' --match-user='dev' --kill --mail --weixin
58 |
59 | 后台运行
60 |
61 | shell> nohup php pt-kill.php -u admin -p 123456 -h 10.10.159.31 -P 3306 -B 10 -I 15 --match-info='select|alter' --match-user='dev' --kill --mail --weixin --daemon 1 &
62 |
63 | 关闭后台运行
64 |
65 | shell> php pt-kill.php --daemon 0
66 |
67 | 以上是工具的使用方法和参数选项。
68 | 这里说下比较重要的参数:
69 |
70 | 1、--kill 如果想杀掉慢查询,那么在后面添加该选项;
71 |
72 | 2、--match-info 可以单独使用,也可以和--match-user结合一起使用;
73 |
74 | 3、--daemon 1 是开启后台守护进程,如果不添加该选择,可以用系统的crontab代替。
75 | 该选项要和-I 10(秒)配合一起使用,即每休眠10秒监控一次。0为关闭后台守护进程。
76 |
77 | 4、--mail 为开启发送邮件报警,需先设置smtp_config.php,改成你自己的邮箱账号信息
78 |
79 | smtp_config.php
80 |
81 | ******************** 配置信息 ********************************
82 | $smtpserver = "smtp.126.com";//SMTP服务器
83 | $smtpserverport = 25;//SMTP服务器端口
84 | $smtpusermail = "chunyang_he@126.com";//SMTP服务器的用户邮箱
85 | $smtpemailto = 'chunyang_he@126.com';//发送给谁
86 | $smtpuser = "chunyang_he@126.com";//SMTP服务器的用户帐号,注:部分邮箱只需@前面的用户名
87 | $smtppass = "123456";//SMTP服务器的授权码
88 | $mailtitle = "警告!出现卡顿慢SQL,请及时优化处理!";//邮件主题
89 | $mailcontent = "
".$content."
";//邮件内容
90 | $mailtype = "HTML";//邮件格式(HTML/TXT),TXT为文本邮件
91 | ************************ 配置信息 ****************************
92 |
93 | 5、--weixin 为开启发送微信报警,需要先安装下simplejson-3.8.2.tar.gz
94 |
95 | shell> tar zxvf simplejson-3.8.2.tar.gz
96 |
97 | shell> cd simplejson-3.8.2
98 |
99 | shell> python setup.py build
100 |
101 | shell> python setup.py install
102 |
103 |
104 | 然后编辑pt-kill.php脚本
105 |
106 | 找到
107 |
108 | $status1 = system("/usr/bin/python wechat.py 'hcymysql' {$row['DB']}库出现卡顿慢SQL! '{$content1}'");
109 |
110 | 将其'hcymysql'我的微信号换成你自己的即可。
111 |
112 | 微信企业号设置
113 |
114 | 移步https://www.cnblogs.com/linuxprobe/p/5717776.html 看此教程配置。
115 |
116 | 6、会在工具目录下生成kill.txt文件保存慢SQL。
117 |
118 | shell> cat kill.txt
119 |
120 | 2018-11-27 16:41:22
121 |
122 | 用户名:root
123 |
124 | 来源IP:localhost
125 |
126 | 数据库名:hcy
127 |
128 | 执行时间:18
129 |
130 | SQL语句:select sleep(60)
131 |
132 |
133 | 7、默认只杀连接中的慢SQL,保留会话连接,如果想把连接也杀掉,去掉QUERY
134 |
135 | 修改pt-kill.php
136 |
137 | //$kill_sql = "KILL QUERY {$row['ID']}";
138 |
139 | $kill_sql = "KILL {$row['ID']}";
140 |
141 | 具体演示请看“pt_kill演示录像.avi”
142 |
143 |
144 |
--------------------------------------------------------------------------------
/Smtp.class.php:
--------------------------------------------------------------------------------
1 | debug = FALSE;
45 |
46 | $this->smtp_port = $smtp_port;
47 |
48 | $this->relay_host = $relay_host;
49 |
50 | $this->time_out = 30; //is used in fsockopen()
51 |
52 |
53 | $this->auth = $auth;//auth
54 |
55 | $this->user = $user;
56 |
57 | $this->pass = $pass;
58 |
59 |
60 | $this->host_name = "localhost"; //is used in HELO command
61 | $this->log_file = "";
62 |
63 | $this->sock = FALSE;
64 |
65 | }
66 |
67 | /* Main Function */
68 |
69 | function sendmail($to, $from, $subject = "", $body = "", $mailtype, $cc = "", $bcc = "", $additional_headers = "")
70 | {
71 |
72 | $mail_from = $this->get_address($this->strip_comment($from));
73 |
74 | $body = preg_replace("/(^|(\r\n))(\.)/", "\1.\3", $body);
75 |
76 | $header = "MIME-Version:1.0\r\n";
77 |
78 | if($mailtype=="HTML"){
79 |
80 | $header .= "Content-Type:text/html\r\n";
81 |
82 | }
83 |
84 | $header .= "To: ".$to."\r\n";
85 |
86 | if ($cc != "") {
87 |
88 | $header .= "Cc: ".$cc."\r\n";
89 |
90 | }
91 |
92 | $header .= "From: $from<".$from.">\r\n";
93 |
94 | $header .= "Subject: ".$subject."\r\n";
95 |
96 | $header .= $additional_headers;
97 |
98 | $header .= "Date: ".date("r")."\r\n";
99 |
100 | $header .= "X-Mailer:By Redhat (PHP/".phpversion().")\r\n";
101 |
102 | list($msec, $sec) = explode(" ", microtime());
103 |
104 | $header .= "Message-ID: <".date("YmdHis", $sec).".".($msec*1000000).".".$mail_from.">\r\n";
105 |
106 | $TO = explode(",", $this->strip_comment($to));
107 |
108 | if ($cc != "") {
109 |
110 | $TO = array_merge($TO, explode(",", $this->strip_comment($cc)));
111 |
112 | }
113 |
114 | if ($bcc != "") {
115 |
116 | $TO = array_merge($TO, explode(",", $this->strip_comment($bcc)));
117 |
118 | }
119 |
120 | $sent = TRUE;
121 |
122 | foreach ($TO as $rcpt_to) {
123 |
124 | $rcpt_to = $this->get_address($rcpt_to);
125 |
126 | if (!$this->smtp_sockopen($rcpt_to)) {
127 |
128 | $this->log_write("Error: Cannot send email to ".$rcpt_to."\n");
129 |
130 | $sent = FALSE;
131 |
132 | continue;
133 |
134 | }
135 |
136 | if ($this->smtp_send($this->host_name, $mail_from, $rcpt_to, $header, $body)) {
137 |
138 | $this->log_write("E-mail has been sent to <".$rcpt_to.">\n");
139 |
140 | } else {
141 |
142 | $this->log_write("Error: Cannot send email to <".$rcpt_to.">\n");
143 |
144 | $sent = FALSE;
145 |
146 | }
147 |
148 | fclose($this->sock);
149 |
150 | $this->log_write("Disconnected from remote host\n");
151 |
152 | }
153 |
154 | return $sent;
155 |
156 | }
157 |
158 | /* Private Functions */
159 |
160 | function smtp_send($helo, $from, $to, $header, $body = "")
161 | {
162 |
163 | if (!$this->smtp_putcmd("HELO", $helo)) {
164 |
165 | return $this->smtp_error("sending HELO command");
166 |
167 | }
168 |
169 | //auth
170 | if($this->auth){
171 |
172 | if (!$this->smtp_putcmd("AUTH LOGIN", base64_encode($this->user))) {
173 |
174 | return $this->smtp_error("sending HELO command");
175 |
176 | }
177 |
178 | if (!$this->smtp_putcmd("", base64_encode($this->pass))) {
179 |
180 | return $this->smtp_error("sending HELO command");
181 |
182 | }
183 |
184 | }
185 |
186 |
187 | if (!$this->smtp_putcmd("MAIL", "FROM:<".$from.">")) {
188 |
189 | return $this->smtp_error("sending MAIL FROM command");
190 |
191 | }
192 |
193 | if (!$this->smtp_putcmd("RCPT", "TO:<".$to.">")) {
194 |
195 | return $this->smtp_error("sending RCPT TO command");
196 |
197 | }
198 |
199 | if (!$this->smtp_putcmd("DATA")) {
200 |
201 | return $this->smtp_error("sending DATA command");
202 |
203 | }
204 |
205 | if (!$this->smtp_message($header, $body)) {
206 |
207 | return $this->smtp_error("sending message");
208 |
209 | }
210 |
211 | if (!$this->smtp_eom()) {
212 |
213 | return $this->smtp_error("sending . [EOM]");
214 |
215 | }
216 |
217 | if (!$this->smtp_putcmd("QUIT")) {
218 |
219 | return $this->smtp_error("sending QUIT command");
220 |
221 | }
222 |
223 | return TRUE;
224 |
225 | }
226 |
227 | function smtp_sockopen($address)
228 | {
229 |
230 | if ($this->relay_host == "") {
231 |
232 | return $this->smtp_sockopen_mx($address);
233 |
234 | } else {
235 |
236 | return $this->smtp_sockopen_relay();
237 |
238 | }
239 |
240 | }
241 |
242 | function smtp_sockopen_relay()
243 | {
244 |
245 | $this->log_write("Trying to ".$this->relay_host.":".$this->smtp_port."\n");
246 |
247 | $this->sock = @fsockopen($this->relay_host, $this->smtp_port, $errno, $errstr, $this->time_out);
248 |
249 | if (!($this->sock && $this->smtp_ok())) {
250 |
251 | $this->log_write("Error: Cannot connenct to relay host ".$this->relay_host."\n");
252 |
253 | $this->log_write("Error: ".$errstr." (".$errno.")\n");
254 |
255 | return FALSE;
256 |
257 | }
258 |
259 | $this->log_write("Connected to relay host ".$this->relay_host."\n");
260 |
261 | return TRUE;
262 |
263 | }
264 |
265 | function smtp_sockopen_mx($address)
266 | {
267 |
268 | $domain = preg_replace("/^.+@([^@]+)$/", "\1", $address);
269 |
270 | if (!@getmxrr($domain, $MXHOSTS)) {
271 |
272 | $this->log_write("Error: Cannot resolve MX \"".$domain."\"\n");
273 |
274 | return FALSE;
275 |
276 | }
277 |
278 | //专注与php学习 http://www.daixiaorui.com 欢迎您的访问
279 |
280 | foreach ($MXHOSTS as $host) {
281 |
282 | $this->log_write("Trying to ".$host.":".$this->smtp_port."\n");
283 |
284 | $this->sock = @fsockopen($host, $this->smtp_port, $errno, $errstr, $this->time_out);
285 |
286 | if (!($this->sock && $this->smtp_ok())) {
287 |
288 | $this->log_write("Warning: Cannot connect to mx host ".$host."\n");
289 |
290 | $this->log_write("Error: ".$errstr." (".$errno.")\n");
291 |
292 | continue;
293 |
294 | }
295 |
296 | $this->log_write("Connected to mx host ".$host."\n");
297 |
298 | return TRUE;
299 |
300 | }
301 |
302 | $this->log_write("Error: Cannot connect to any mx hosts (".implode(", ", $MXHOSTS).")\n");
303 |
304 | return FALSE;
305 |
306 | }
307 |
308 | function smtp_message($header, $body)
309 | {
310 |
311 | fputs($this->sock, $header."\r\n".$body);
312 |
313 | $this->smtp_debug("> ".str_replace("\r\n", "\n"."> ", $header."\n> ".$body."\n> "));
314 |
315 | return TRUE;
316 |
317 | }
318 |
319 | function smtp_eom()
320 | {
321 |
322 | fputs($this->sock, "\r\n.\r\n");
323 |
324 | $this->smtp_debug(". [EOM]\n");
325 |
326 | return $this->smtp_ok();
327 |
328 | }
329 |
330 | function smtp_ok()
331 | {
332 |
333 | $response = str_replace("\r\n", "", fgets($this->sock, 512));
334 |
335 | $this->smtp_debug($response."\n");
336 |
337 | if (!preg_match("/^[23]/", $response)) {
338 |
339 | fputs($this->sock, "QUIT\r\n");
340 |
341 | fgets($this->sock, 512);
342 |
343 | $this->log_write("Error: Remote host returned \"".$response."\"\n");
344 |
345 | return FALSE;
346 |
347 | }
348 |
349 | return TRUE;
350 |
351 | }
352 |
353 | function smtp_putcmd($cmd, $arg = "")
354 | {
355 |
356 | if ($arg != "") {
357 |
358 | if($cmd=="") $cmd = $arg;
359 |
360 | else $cmd = $cmd." ".$arg;
361 |
362 | }
363 |
364 | fputs($this->sock, $cmd."\r\n");
365 |
366 | $this->smtp_debug("> ".$cmd."\n");
367 |
368 | return $this->smtp_ok();
369 |
370 | }
371 |
372 | function smtp_error($string)
373 | {
374 |
375 | $this->log_write("Error: Error occurred while ".$string.".\n");
376 |
377 | return FALSE;
378 |
379 | }
380 |
381 | function log_write($message)
382 | {
383 |
384 | $this->smtp_debug($message);
385 |
386 | if ($this->log_file == "") {
387 |
388 | return TRUE;
389 |
390 | }
391 |
392 | $message = date("M d H:i:s ").get_current_user()."[".getmypid()."]: ".$message;
393 |
394 | if (!@file_exists($this->log_file) || !($fp = @fopen($this->log_file, "a"))) {
395 |
396 | $this->smtp_debug("Warning: Cannot open log file \"".$this->log_file."\"\n");
397 |
398 | return FALSE;
399 |
400 | }
401 |
402 | flock($fp, LOCK_EX);
403 |
404 | fputs($fp, $message);
405 |
406 | fclose($fp);
407 |
408 |
409 | return TRUE;
410 |
411 | }
412 |
413 |
414 | function strip_comment($address)
415 | {
416 |
417 | $comment = "/\([^()]*\)/";
418 |
419 | while (preg_match($comment, $address)) {
420 |
421 | $address = preg_replace($comment, "", $address);
422 |
423 | }
424 |
425 | return $address;
426 |
427 | }
428 |
429 |
430 | function get_address($address)
431 | {
432 |
433 | $address = preg_replace("/([ \t\r\n])+/", "", $address);
434 |
435 | $address = preg_replace("/^.*<(.+)>.*$/", "\1", $address);
436 |
437 | return $address;
438 |
439 | }
440 |
441 | function smtp_debug($message)
442 | {
443 |
444 | if ($this->debug) {
445 |
446 | echo $message;
447 |
448 | }
449 |
450 | }
451 |
452 | }
453 |
454 |
--------------------------------------------------------------------------------
/pt-kill.php:
--------------------------------------------------------------------------------
1 | yum install -y php-process php php-mysql
14 | *
15 | */
16 |
17 | ini_set('date.timezone','Asia/Shanghai');
18 | error_reporting(7);
19 |
20 | function Usage(){
21 | echo "\e[38;5;11m
22 | Usage:
23 | Options:
24 | -u username
25 | -p password
26 | -h host ip
27 | -P port
28 | -B busytime time seconds 设置慢SQL执行时间触发报警
29 | -I interval time seconds 设置守护进程下间隔监测时间
30 | --kill 如果想杀掉慢查询,加上该选项。
31 | --match-info 匹配杀掉SELECT|INSERT|UPDATE语句
32 | --match-user 匹配杀掉的用户
33 | --daemon 1开启后台守护进程,0关闭后台守护进程
34 | --mail 开启发送邮件报警
35 | --weixin 开启发送微信报警
36 | --help Help
37 |
38 | Example :
39 | 前台运行
40 | shell> php pt-kill.php -u admin -p 123456 -h 10.10.159.31 -P 3306 -B 10 --match-info='select|alter' --match-user='dev' --kill --mail --weixin
41 |
42 | 后台运行
43 | shell> nohup php pt-kill.php -u admin -p 123456 -h 10.10.159.31 -P 3306 -B 10 -I 15 --match-info='select|alter' --match-user='dev' --kill --mail --weixin --daemon 1 &
44 |
45 | 关闭后台运行
46 | shell> php pt-kill.php --daemon 0
47 | \e[0m" .PHP_EOL;
48 | }
49 |
50 | $shortopts = "u:";
51 | $shortopts .= "p:";
52 | $shortopts .= "h:";
53 | $shortopts .= "P:";
54 | $shortopts .= "B:";
55 | $shortopts .= "I:";
56 |
57 | $longopts = array(
58 | "kill",
59 | "match-info::",
60 | "match-user::",
61 | "daemon:",
62 | "mail",
63 | "weixin",
64 | "help",
65 | );
66 |
67 | $options = getopt($shortopts, $longopts);
68 |
69 | if(empty($options) || isset($options['help'])){
70 | Usage();
71 | exit;
72 | }
73 |
74 | if(!isset($options['daemon'])){
75 | Slowsql();
76 | exit;
77 | }
78 | else{
79 | if($options['daemon'] != 0){
80 | if(!isset($options['I'])){
81 | die("请设置间隔时间 -I 5(单位秒)"."\n");
82 | }
83 | }
84 | $deamon = new Daemon($options['I']);
85 | $deamon->run($options['daemon']);
86 | }
87 |
88 | function Slowsql(){
89 |
90 | global $options;
91 |
92 | $con = mysqli_connect("{$options['h']}","{$options['u']}","{$options['p']}","information_schema","{$options['P']}")
93 | or die("数据库链接错误"."\n".mysqli_error($con));
94 | mysqli_query($con,"set names utf8");
95 |
96 | if(isset($options['match-info'])){
97 | $get_match_info = "SELECT ID,USER,HOST,DB,TIME,COMMAND,STATE,INFO FROM information_schema.PROCESSLIST
98 | WHERE TIME >= '{$options['B']}' AND INFO REGEXP '{$options['match-info']}'";
99 | $result = mysqli_query($con,$get_match_info);
100 | }
101 | else if(isset($options['match-user'])){
102 | echo "\e[38;5;196m没有匹配到SELECT|INSERT|UPDATE|DELETE等DML/DDL语句,退出主程序。\e[0m"."\n"; exit;
103 | }
104 | else if(isset($options['match-info']) && isset($options['match-user'])){
105 | $get_match_user_info = "SELECT ID,USER,HOST,DB,TIME,COMMAND,STATE,INFO FROM information_schema.PROCESSLIST
106 | WHERE TIME >= '{$options['B']}' AND (INFO REGEXP '{$options['match-info']}'
107 | AND USER REGEXP '{$options['u']}')";
108 | $result = mysqli_query($con,$get_match_user_info);
109 | }
110 | else{ echo "\e[38;5;196m没有匹配到SELECT|INSERT|UPDATE|DELETE等DML/DDL语句,退出主程序。\e[0m"."\n\n"; exit;}
111 |
112 | $rowcount=mysqli_num_rows($result);
113 | if ($rowcount == 0){
114 | if(file_exists(dirname(__FILE__)."/kill.txt")){
115 | rename(dirname(__FILE__)."/kill.txt","kill_".date('Y-m-d_H:i:s')."_history.txt");
116 | //file_put_contents(dirname(__FILE__).'/kill.txt',"");
117 | }
118 | echo "\e[38;5;10m".date('Y-m-d H:i:s')." 未检测出当前执行中的卡顿慢SQL。\e[0m" .PHP_EOL;
119 | }
120 | else{
121 | echo "\n";
122 | echo "\e[38;5;196m".date('Y-m-d H:i:s')." 警告!出现卡顿慢SQL,请及时排查问题。\e[0m" .PHP_EOL;
123 | while($row = mysqli_fetch_array($result)){
124 | file_put_contents(dirname(__FILE__).'/kill.txt', date('Y-m-d H:i:s')."\n".
125 | "用户名:".$row['USER']."\n".
126 | "来源IP:".$row['HOST']."\n".
127 | "数据库名:".$row['DB']."\n".
128 | "执行时间:".$row['TIME']."\n".
129 | "SQL语句:".$row['INFO']."\n".
130 | "\n", FILE_APPEND);
131 |
132 | if(isset($options['kill'])){
133 | echo "\e[38;5;11m自动杀死执行时间超过{$options['B']}秒的慢SQL\e[0m" .PHP_EOL;
134 | $kill_sql = "KILL QUERY {$row['ID']}"; //默认只杀连接中的慢SQL,保留会话连接,如果想把连接也杀掉,去掉QUERY
135 | //$kill_sql = "KILL {$row['ID']}";
136 | mysqli_query($con,$kill_sql);
137 | }
138 |
139 | //调用发邮件对象
140 | if(isset($options['mail'])){
141 | $content = nl2br(file_get_contents(dirname(__FILE__).'/kill.txt'));
142 | require "smtp_config.php";
143 | $smtp = new Smtp($smtpserver,$smtpserverport,true,$smtpuser,$smtppass);//这里面的一个true是表示使用身份验证,否则不使用身份验证.
144 | $smtp->debug = false;//是否显示发送的调试信息
145 | $status = $smtp->sendmail($smtpemailto, $smtpusermail, $mailtitle, $mailcontent, $mailtype);
146 |
147 | if($status==""){
148 | echo "对不起,邮件发送失败!请检查邮箱填写是否有误。";
149 | }else{
150 | echo "恭喜!邮件发送成功!!" .PHP_EOL;}
151 | }
152 |
153 | //调用发微信wechat.py脚本
154 | if(isset($options['weixin'])){
155 | $content1 = file_get_contents(dirname(__FILE__).'/kill.txt');
156 | $status1 = system("/usr/bin/python wechat.py 'hcymysql' {$row['DB']}库出现卡顿慢SQL! '{$content1}'");
157 |
158 | if($status1==""){
159 | echo "对不起,微信发送失败!请检查wechat.py脚本设置是否有误。";
160 | }else{
161 | echo "恭喜!微信发送成功!!" .PHP_EOL;}
162 | }
163 | }
164 | }
165 | }
166 |
167 | class Daemon {
168 | private $pidfile;
169 | private $sleep_time;
170 |
171 | function __construct($st) {
172 | $this->pidfile = dirname(__FILE__).'/pt-kill.pid';
173 | $this->sleep_time = $st;
174 | }
175 |
176 | private function startDeamon() {
177 | if (file_exists($this->pidfile)) {
178 | echo "The file $this->pidfile exists." . PHP_EOL;
179 | exit();
180 | }
181 |
182 | $pid = pcntl_fork();
183 | if ($pid == -1) {
184 | die('could not fork\n');
185 | } else if ($pid) {
186 | echo 'start ok' . PHP_EOL;
187 | exit($pid);
188 | } else {
189 | file_put_contents($this->pidfile, getmypid());
190 | return getmypid();
191 | }
192 | }
193 |
194 | private function start(){
195 | $pid = $this->startDeamon();
196 | while (true) {
197 | Slowsql();
198 | sleep($this->sleep_time);
199 | }
200 | }
201 |
202 | private function stop(){
203 | if (file_exists($this->pidfile)) {
204 | $pid = file_get_contents($this->pidfile);
205 | posix_kill($pid, 9);
206 | unlink($this->pidfile);
207 | }
208 | }
209 |
210 | public function run($param) {
211 | if($param == 1) {
212 | $this->start();
213 | }else if($param == 0) {
214 | $this->stop();
215 | echo "pt-kill.php后台守护进程已停止。". PHP_EOL;
216 | }
217 | else{
218 | echo 'daemon传参错误,请输入0关闭后台进程,1开启后台线程。'. PHP_EOL;
219 | }
220 | }
221 |
222 | }
223 |
224 | ?>
225 |
226 |
--------------------------------------------------------------------------------
/pt_kill演示录像.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hcymysql/pt-kill/6ed17c21640c9c93e826307140c5759d5dd3fabd/pt_kill演示录像.zip
--------------------------------------------------------------------------------
/simplejson-3.8.2.tar.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hcymysql/pt-kill/6ed17c21640c9c93e826307140c5759d5dd3fabd/simplejson-3.8.2.tar.gz
--------------------------------------------------------------------------------
/smtp_config.php:
--------------------------------------------------------------------------------
1 | ".$content."";//邮件内容
15 | $mailtype = "HTML";//邮件格式(HTML/TXT),TXT为文本邮件
16 | //************************ 配置信息 ****************************
17 |
18 | ?>
19 |
--------------------------------------------------------------------------------
/wechat.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | #_*_coding:utf-8 _*_
3 |
4 |
5 | import urllib,urllib2
6 | import json
7 | import sys
8 | import simplejson
9 |
10 | reload(sys)
11 | sys.setdefaultencoding('utf-8')
12 |
13 |
14 | def gettoken(corpid,corpsecret):
15 | gettoken_url = 'https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=' + corpid + '&corpsecret=' + corpsecret
16 | print gettoken_url
17 | try:
18 | token_file = urllib2.urlopen(gettoken_url)
19 | except urllib2.HTTPError as e:
20 | print e.code
21 | print e.read().decode("utf8")
22 | sys.exit()
23 | token_data = token_file.read().decode('utf-8')
24 | token_json = json.loads(token_data)
25 | token_json.keys()
26 | token = token_json['access_token']
27 | return token
28 |
29 |
30 |
31 | def senddata(access_token,user,subject,content):
32 |
33 | send_url = 'https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=' + access_token
34 | send_values = {
35 | "touser":user, #企业号中的用户帐号,在zabbix用户Media中配置,如果配置不正常,将按部门发送。
36 | "toparty":"1", #企业号中的部门id。
37 | "msgtype":"text", #消息类型。
38 | "agentid":"1", #企业号中的应用id。
39 | "text":{
40 | "content":subject + '\n' + content
41 | },
42 | "safe":"0"
43 | }
44 | # send_data = json.dumps(send_values, ensure_ascii=False)
45 | send_data = simplejson.dumps(send_values, ensure_ascii=False).encode('utf-8')
46 | send_request = urllib2.Request(send_url, send_data)
47 | response = json.loads(urllib2.urlopen(send_request).read())
48 | print str(response)
49 |
50 |
51 | if __name__ == '__main__':
52 | user = str(sys.argv[1]) #zabbix传过来的第一个参数
53 | subject = str(sys.argv[2]) #zabbix传过来的第二个参数
54 | content = str(sys.argv[3]) #zabbix传过来的第三个参数
55 |
56 | corpid = 'wxaxxxxxxxxxxxxxx' #CorpID是企业号的标识
57 | corpsecret = 'vK4Foxxxxxxxxxxxxxxxxxxxx' #corpsecretSecret是管理组凭证密钥
58 | accesstoken = gettoken(corpid,corpsecret)
59 | senddata(accesstoken,user,subject,content)
60 |
--------------------------------------------------------------------------------