|
----------------assayLog.sh---------
#!/bin/bash
# check if the letter is send to all email,and call php assay this letter log
# 1. can run this sh by the root crontab every hour;
# 2. may sure only one sh run one times,sh first check if another sh runing,if yes exit self;
# 3. you can run it check error on shell,and may sure is all ok for add to crontab
# 4. crontab setting must like under line,must give domain by argv[1],because this sh use it concat like xx_DBID@domain find if the postfix queue exist it,and may sure the letter all send over, and can assay the letter log;
# * */1 * * * /var/www/edm/sh/assayLog.sh myhrd.cn
# 5. you can > xxx.txt to look cron result
#----------install-------
# run this command by root: chmod 705 ./assayLog.sh
getShPath () {
if [ "`expr \"$0\" : '\(.\)'`" == "/" ];then #like /var/www/sh.sh
echo "$0"
return 0;
fi
if [ "`expr \"$0\" : '\(.\)'`" == "." ];then #like ./sh.sh or ./../../sh.sh
local newDir=${0#'./'}
echo "`pwd`/$newDir"
return 0;
fi
echo "$0" #unkown type
return 0
}
myDomain=$1 #get domain setting
if [ -z "$myDomain" ]; then
echo "must give you domain by argv[1] exit"
exit 0
fi
echo "set domain: $myDomain"
fsh=`ps ax` # don't include |grep may sure ps don't include sub shell
if [ "$UID" -ne 0 ];then
echo "this sh must run on root"
exit 0
fi
shPid=" $$ "
echo "sh pid $shPid"
shName=`basename $0`
fsh=`echo "$fsh" | grep "[0-9]\+ /.*/bash .*/sh/$shName"`
echo $fsh
fsh="none `echo $fsh` " # at the front add space,and replace /r/n
fsh=${fsh/$shPid/$shName}
echo "$fsh"
fsh=`expr "$fsh" : ".* \([0-9]\+\) "`
echo $fsh
if [ -n "$fsh" ];then
echo "another sh runing exit self"
exit 0
fi
logDir=`getShPath`
logDir="`dirname $logDir`/log/*" #must a array
echo "sh dir : $logDir"
for fileName in $logDir;do #list current dir files
echo "find:$fileName"
bName=`basename $fileName`
if [ -d "$fileName" ];then
echo "it is dir,skip"
elif [ -z `expr "$bName" : '\([0-9]\+\)$'` ];then #is file but no number name
echo "$fileName is't a log(DB ID),skip"
else #db id filename
queue=`sudo -u root postqueue -p` # must runt postqueue by root
echo "queue list under
$queue"
len=${#queue}
mail='_'
mail+=$bName
mail+='@'
mail+=$myDomain
queue=${queue//$mail/'*'}
nLen=${#queue}
echo "$len $nLen
$queue"
if [ $nLen -eq $len ];then #queue doned
php="php /var/www/edm/postfix.php $bName"
echo "call $php"
php=`$php`
wait #wait for php exit
echo $php
notDell=`expr "echo $php" : '.*\(_sh_notDell_sh_\)'` #php may suer return this by doing this letter
if [ -z "$notDell" ];then # return don't include notDell,to dell log
echo "dell it: `rm $fileName`"
else
echo 'letter queue,no dell log'
fi
else
echo 'letter on queue, skip'
fi
fi
done;
exit 0;
----------------功能介绍----------
获取log目录中的文件,检测postqueue -p是否不存在此发件人来确认发送完成.然后调用php分析日志,php分析完成后sh删除日志文件
----------------------分析php--------
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
@set_time_limit(-1);//设置脚本超时时间,单位秒
class Postfix extends CI_Controller {
/*
* 分析postfix日志,并生成统计数据
* 如果检测队列还在发送中,可能是因为postfix发送速度过快.smtp过慢,导致队列已空,sh错误判断调用这个php,所以.
* 如果暂不能删除本信件日志,需要返回中包含有 _sh_notDell_sh_
* 最好返回整串中不能换行
*/
public function index(){
$this->output->set_header('Content-Type:text/html; charset=UTF-8');
$this->benchmark->mark('pA');
$id = empty($GLOBALS['argv']) ? 0 : trim($GLOBALS['argv'][1]);
if (empty($id)) {
echo "empty id";
} else {
$row = $this->db->query("SELECT * FROM letter_queue WHERE id = " .(int)$id);
if ($row->num_rows()) {//postfix队列是空,但edm队列非空,暂停读取
echo 'edm queue doing.(_sh_notDell_sh_)';
} else {
$logPath = str_replace("\\", '/', dirname(dirname(dirname(dirname(__FILE__)))).'/sh/log/');
if (! file_exists($logPath . $id)) {
echo 'log not exist';
} else if (! is_readable($logPath . $id)) {
echo 'php can\'t read it (_sh_notDell_sh_)';
} else if (! $fp = fopen($logPath . $id, 'r')) {
echo 'php open it fail (_sh_notDell_sh_)';
} else {
$errors = array (
'host' => array(0, '主机出错')
, 'user' => array(0, '用户出错')
, 'reject' => array(0, '拒收')
, 'other' => array(0, '其它')
);
while (!feof($fp)) {
$line = fgets($fp);
if (
(false !== stripos($line, 'Domain not found'))
|| (false !== stripos($line, ' status=deferred ')) //主机问题,延时发送
|| (false !== stripos($line, 'Service unavailable')) //主机问题,延时发送
) { //域名有误
$errors['host'][0]++;
} else if (
(false !== stripos($line, ' said: 550 '))
|| (false !== stripos($line, ' said: 503 ')) //account isn't a local account me
|| (false !== stripos($line, ' said: 501 ')) //bad address
|| (false !== stripos($line, ' full ')) //mailbox full
) {//用户错误
$errors['user'][0]++;
} else if (
(false !== stripos($line, ' forbidden'))
|| (false !== stripos($line, ' refused'))
|| (false !== stripos($line, ' block'))
|| (false !== stripos($line, ' banned '))
|| (false !== stripos($line, ' SPAM '))
|| (false !== stripos($line, ' REJECT'))
|| (false !== stripos($line, 'Relaying denied'))
) {//用户拒绝
$errors['reject'][0]++;
} else {//其它原因出错
$errors['other'][0]++;
}
}
fclose($fp);
foreach ($errors as $key => $val) {
$errors[$key] = $val[1] .':'. $val[0];
}
$errors = implode(';', $errors);
echo "{$logPath}{$id};{$errors} \n";
$this->db->update('letters', array('fail' => $errors), array('id' => $id));
}
}
}
echo "execute time :" .$this->benchmark->elapsed_time('pA', 'pB'). "\n";
}
}
/*
* end
*/
--------------------功能---------------
根据日志出错提示,进行归类汇总
|
|