共计 8460 个字符,预计需要花费 22 分钟才能阅读完成。
情景描述
公司 web 服务器分为三个集群:前台(包括 www、news、m 等站点);图片(包括 img、static 等站点);后台(包括 user、interface 等站点)。这种情况下如何使用 awstats 进行日志分析呢?
这个需求我们很容易想到其中的几个“关键点”
- 如何将各台 web server 上的站点日志拷贝到 awstats server 上的合适位置以备处理呢?这好说,写脚本用 scp 或者 rsync 嘛!ok,再想一步,如何在 server 数量或者 server 上站点发生变化时,脚本依然能够正确的完成任务呢?这就要各 server 上关于日志名称、日志及其备份目录、日志轮转等方面做统一约定了,脚本按照这个约定才能“以不变应万变”。
- 一个站点的访问日志势必会有多份,awstats 如何处理呢?还好这一点 awstats 已经帮我们想好了,在 awstats 配置文件里关于“LogFile=”部分的注释已经写得很清楚。
- 这么多站点,最好有一个统一的入口页面,而且增减站点入口要简单,用着才方便。
基于以上几点,本文分享一种思路,若有更优的方法,还请不吝指教。
文章分四个部分:前提及约定 ;awstats 配置要点和 FastCGI 方式配置; 集中展示页面(JavaScript 实现);日志收集处理脚本
前提及约定
先看下我的约定(其实某些约定即使在本文之外也是很有必要的,例如 1、2。脚本的正常运行依赖于这些约定):
- 日志命名:如 www.abc.com 访问日志命名为 www.access.log;日志存放位置:当前的日志存在于 /nginx_log 目录,日志备份存储于 /nginx_log/backup。看下图就一目了然了
-
日志轮转:我的 web server 为 nginx,通过日志切割脚本自动在 0 点重新生成日志,并将旧日志文件以前一天的日期为后缀命名(例如“images.access.log.2015-12-02”)移动到日志备份目录。
看下日志切割脚本(在每台 web server 定时 0 点执行)
cat rotate_nginx_logs.sh
#!/bin/sh logs_path="/nginx_log" ### 日志存放路径 logs_bak_dir="/nginx_log/backup" ### 日志备份目录 yesterday=`date -d "1 day ago" +%` pid_file=`cat /usr/local/nginx/nginx.pid` ###nginx pid 文件 cd $logs_path for log in `ls *.log`;do mv $log $logs_bak_dir/$log.$yesterday done ### 重命名日志文件 kill -USR1 $pid_file ### 告知 nginx 重新生成日志 cd $logs_bak_dir find . -mtime +5|xargs rm -f ### 删除 backup 目录下超过 5 天的备份
-
每天凌晨自动完成这一系列任务,页面最新可显示昨日的分析结果
-
各站点日志文件拉取到 awstats server 后的存储形式
- awstats server 设置对所有相关 web server 的免秘钥登陆,以便拉取日志
awstats 配置要点和 FastCGI 方式配置
这里不展开详细的安装步骤,只说明一些配置选项以及如何配置动态模式。
awstats 有两种方式展示分析结果:
一种是命令行生成 html 格式的分析页面;另一种是在浏览器通过向 CGI 网关传递参数来动态生成分析结果。
其实在原理上,这两种形式都需要“perl awstats.pl -config=mysite.conf -update”命令定时更新生成指定站点的“数据文件”(即经过 awstats.pl 分析日志生成的中间文件),然后可以分两种方法(对中间文件进行处理)生成我们看到的分析页面:
- 通过“perlawstats.pl -config=www.conf -output -staticlinks > www.html”命令生成 html 文件用于展示
- web 服务器通过 FastGCI 调用类似“http://awstats.abc.com/cgi-bin/awstats.pl?config=/usr/local/services/awstats-7.4/etc/www.conf”的 url 在访问时动态生成分析页面
两种方式各有优缺:第一种定时生成 html 文件,访问时页面加载快,但是页面布局使用起来 不方便也不美观 ;第二种在打开页面时需要临时处理“数据文件”生成 html,页面加载速度根据“数据文件”大小不同会有不同程度延迟,但是动态形式的页面布局 看着舒服用着顺手(所以我选择 fastcgi 模式)。
fastcgi 模式页面如下图所示
来看下我的 awstats 目录,其中我增加了三个目录,如下图
然后来看下配置文件里需要注意的几个地方:
### 因为我们每一个站点的日志文件不止一份,所以 LogFile 必须按照以下模式配置
LogFile="/usr/local/services/awstats-7.4/tools/logresolvemerge.pl /nginx_log/log_analyze/www/*.log* |"
###DirData 按照上图所示,存储于 result 下,例如 result/www result/img 等
DirData="/usr/local/services/awstats-7.4/result/www"
###DirCgi="/awstats" 将此行注释掉
LoadPlugin="decodeutfkeys" ### 将此行的注释打开。否则页面“搜索关键字”可能乱码
同时yum install perl-String-Escape perl-URI-Encode
安装 perl 字符及 URL 解码模块
然后再看“配置文件”的生成管理
各站点的配置文件存放于 awstats/etc 下,如 www.conf,img.conf 等。面对如此多的配置文件,这里写了个简单的小脚本来批量修改 / 生成配置文件。我们只需修改好一份配置文件,再运行该脚本即可(如,以 www.conf 为模板,则执行”sh awstats/shells/batch_conf_file.sh www”) cat awstats/shells/batch_conf_file.sh
#!/bin/sh
### 批量建数据目录,批量 创建各域名配置文件
cd /usr/local/services/awstats-7.4
for i in `ls result` # 这一步需下文的日志收集脚本执行完,在 result 目录下生成了各站点目录才能正确执行
do
if [$1 != $i ];then
echo -e "\n------ create $i.conf -------"
rsync -a etc/$1.conf etc/$i.conf
echo -e "------replace $1 by $i -------"
sed -i "/^[^#].*/ s/$1/$i/g" etc/$i.conf
fi
done
最后来看 fastcgi 模式的配置
- 在 tools/nginx/ 目录下有相关文件
- 将 tools/nginx/awstats-fcgi.php 拷贝至 wwwroot/cgi-bin/fcgi.php
-
修改 tools/nginx/awstats-nginx.conf 文件相关配置,并在 nginx 主配置文件里面引用该文件
server {listen 80; server_name awstats.abc.com; root /usr/local/services/awstats-7.4/wwwroot; #charset utf8; index index.html; # Static awstats files: HTML files stored in DOCUMENT_ROOT/awstats/ location /awstats/classes/ {alias /usr/local/services/awstats-7.4/wwwroot/classes/; } location /awstats/css/ {alias /usr/local/services/awstats-7.4/wwwroot/css/; } location /awstats/icon/ {alias /usr/local/services/awstats-7.4/wwwroot/icon/; } location /awstats-icon/ {alias /usr/local/services/awstats-7.4/wwwroot/icon/; } location /awstats/js/ {alias /usr/local/services/awstats-7.4/wwwroot/js/; } # Dynamic stats. location ~ ^/cgi-bin/(awredir|awstats)\.pl { gzip off; fastcgi_pass 127.0.0.1:9000; fastcgi_param SCRIPT_FILENAME $document_root/cgi-bin/fcgi.php; fastcgi_param X_SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param X_SCRIPT_NAME $fastcgi_script_name; include fastcgi_params; # 下面这三行酌情设置。太小可能会导致页面“链接被重置” fastcgi_connect_timeout 300; fastcgi_send_timeout 300; fastcgi_read_timeout 300; } }
集中展示页面
如果有多个域名的话,每次查看都需要输入对应的一串 url 肯定是很麻烦的。这里用 html 和 JavaScript 写了一个小页面,把所有域名的入口集中到一起,如下图所示
index.html文件内容如下(如有站点的增减,只需在 js 的 vhost 数组对应增减即可)
<html>
<head>
<title>源站日志分析</title>
<style type="text/css">
.wrap{width:1200px;
margin:5px auto;
border:0 solid #000;
}
table {width:660px;
margin:5px auto;
border:2px solid #E0E0E0;
background-color:#F0F0F0;
border-collapse:collapse;
}
td {width:220px;
height:45px;
font-size:1.1em;
text-align:center;
border:0 solid #2894FF;
}
h1 {text-align:center;color:#0072E3;font-family:"Microsoft YaHei",SimSun,BiauKai;}
a {text-decoration:none;color:#0072E3;}
a:hover{color:#FF5809}
</style>
</head>
<body>
<div class="wrap">
<h1>源站日志分析平台</h2>
<script type="text/javascript">
// 域名数组,需要添加或删除域名只需在这里修改即可, 会自动为其设置对应的超链接
var vhost=["www.abc.com",
"m.abc.com",
"news.abc.com",
"static.abc.com",
"images.abc.com",
"bbs.abc.com",
"i.abc.com",
"interface.abc.com",
"open.abc.com",
];
var num=vhost.length; // 域名数量
var j=101; // j 为行 id,100 为了避免跟单元格 id 重复而随意指定
// 利用 JavaScript 创建表格
for (var i=1;i<=num;i++) {if (i==1) {document.write("<table><tr id=\"101\"><td id=\"1\"onmouseover=\"chg_td_bgcolor()\">");
}
else if (i==num) {document.write("<td id=\"" + num + "\" onmouseover=\"chg_td_bgcolor()\"></td></tr></table>")}
else if (i%3==0) {j++; // 每三个单元格一个新行,行号加一
document.write("<td id=\""+ i +"\" onmouseover=\"chg_td_bgcolor()\">"+ i +"</td>");
document.write("</tr><tr id=\""+j +"\">");
}
else {document.write("<td id=\""+ i +"\" onmouseover=\"chg_td_bgcolor()\">"+ i +"</td>");}
}
// 向表格填充内容
for (var tdid=0;tdid<num;tdid++) {// 依顺序获取各 td 元素
var tdnode=document.getElementById(tdid+1);
// 取出每个域名里的主机名,服务器端 awstats 该站点配置文件命名方式为“主机名.conf”
var hostname=vhost[tdid].split(".abc",1);
// 向表格插入域名并且设置超链接,config 文件的位置各位自行设置
tdnode.innerHTML="<a href=\"cgi-bin/awstats.pl?config=/usr/local/services/awstats-7.4/etc/"+hostname+ ".conf\">" +vhost[tdid] +"</a>";
}
// 设置 table 行背景色
for (var x=101;x<=j;x++){var row=document.getElementById(x);
if (x%2==0) {row.style.background="#E0E0E0";
}
}
// 连接在新窗口打开
var allLinks=document.getElementsByTagName("a");
for(var i=0;i!=allLinks.length; i++){allLinks[i].target="_blank";
}
</script>
</div>
</body>
</html>
日志收集、处理
这里我在 awstats server 上写了一套 shell 脚本来实现无论 web server 上运行哪些站点,只要告诉脚本该 server 的 ip 即可将该 server 上所有站点日志拷贝至本机的合适位置以待分析。各 server 的 ip 信息记录于”/root/shells/ips.txt”,每条记录一行,如“web1-192.168.1.1”
来看脚本内容,脚本内注释应该已经比较详细了 cat awstats/shells/cp_logs_for_awstats.sh
#!/bin/sh
log_dir_s=/data/nginx_log/backup # 各台 server 日志文件源目录
log_dir_d=/data/nginx_log/log_analyze # 定义将日志拉取到本地后的存放路径
time1=`date -d "1 day ago" +%F` # 获取一天前的日期
time2=`date -d "2 day ago" +%F`
basedir=/usr/local/services/awstats-7.4
echo -e "`date` 开始拉取日志 \n" >$basedir/logs/cron.log
for server_ip in `cat /root/shells/ips.txt` # 记录需要统计日志的所有主机 ip 和主机名
do
ip=`echo $server_ip|awk -F '-' '{print $2}'` # 获取各 server IP
echo -e "\e[1;32m \n----------rsync logs from $ip----------\e[0m" >>$basedir/logs/cron.log
# 为了减少 ssh 连接,在此步将该 ip 下的所有前一天的 access 日志拷贝至本地 /tmp 下
rsync -avz --compress-level=6 --progress --exclude="default.*" --min-size=1k $ip:$log_dir_s/*access*"$time1" /tmp/
# 取得上一天的日志备份文件名 log_name
for log_name in `cd /tmp/;ls *.access.log*`
do
vhost_name=`echo $log_name|awk -F.access '{print $1}'` # 取得 web server 的 vhost 名
echo -e "\e[1;32m ----- 拷贝 $vhost_name 日志 -----\e[0m" >>$basedir/logs/cron.log
# 在本地建立目录分类存放 cp 过来的日志
if [! -d "$log_dir_d/$vhost_name" ];then
mkdir $log_dir_d/$vhost_name
fi
rm -f $log_dir_d/$vhost_name/*"$time2"*
mv /tmp/$log_name $log_dir_d/$vhost_name/$log_name.$ip # 从 tmp 下依次 mv 日志文件到目标目录
done
done
echo -e "`date` 拉取日志完成 \n" >>$basedir/logs/cron.log
上面的 shell 脚本只是将分散在各 web server 的日志文件按规则拉取到了本地特定目录,接下来的 shell 脚本用来调用 awstats.pl 循环处理各站点日志 cat awstats/shells/cron_awstats_update.sh
#!/bin/sh
#awstats 日志分析
basedir=/usr/local/services/awstats-7.4
cd $basedir
# 循环更新所有站点日志统计信息
echo -e "\e[1;31m-------`date"+%F %T"` 开始处理 ---------\n\e[0m" >>logs/cron.log
for i in `ls result/`
do
echo -e "\e[1;32m -----`date"+%F %T"` 处理 $i 日志 -----\e[0m" >>logs/cron.log
perl wwwroot/cgi-bin/awstats.pl -config=etc/$i.conf -lang=cn -update &>>logs/cron.log
done
echo -e "\e[1;31m\n-------`date"+%F %T"` 处理完成 ---------\e[0m" >>logs/cron.log
这两个脚本作为计划任务在 awstats server 运行,我的 crontab 如下 # 日志分析平台
5 0 * * * /bin/bash /root/shells/cp_logs_to_img2_for_awstats.sh ; /bin/bash /root/shells/cron_awstats_update.sh
至此,这么一套东西就算完成了。
写了这么多,希望我说清楚了。看到此处的伙伴,希望能对你们有些许帮助吧!
AWStats 配置 (Windows + Apache) http://www.linuxidc.com/Linux/2013-09/89710.htm
CentOS 6.3 下 AWStats+GeoIP 实现查看网站访问归属地 http://www.linuxidc.com/Linux/2013-06/85984.htm
Nginx 日志分析 AWStats + JAWStats 安装配置 http://www.linuxidc.com/Linux/2013-06/85567.htm
经典日志分析工具 -AWStats http://www.linuxidc.com/Linux/2012-12/77080.htm
AWStats 日志系统配置文件和错误归纳 http://www.linuxidc.com/Linux/2012-12/75657.htm
使用 AWStats 分析网站日志 - 强大的日志分析工具 http://www.linuxidc.com/Linux/2012-11/74431.htm
如何在 Ubuntu 服务器中配置 AWStats http://www.linuxidc.com/Linux/2015-12/125799.htm
本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-10/136215.htm