月度存档: 7 月 2015 - 第3页

Apache日志的滚动

1、为什么使用日志滚动

  由于Apache 进程本身不负责对日志文件进行滚动,因此必须使用其他程序配置日志滚动。所有的日志文件都会随着时间的推移和访问次数的增加而迅速增长,因此必须对日志文件进行定期清理以免造成磁盘空间的不必要的浪费。同时也加快了管理员查看日志所用的时间,因为打开小文件的速度比打开大文件的速度要快。

  2、使用命令使用空的日志文件

  要使系统重新使用空的日志文件,可以执行如下的命令:
cd /opt/coolstack/apache2/log
  mv access_log access_log.old
  mv error_log error_log.old
  /opt/coolstack/apache2/bin/apachectl graceful
  sleep 800
  gzip access_log.old error_log.old
  上面的指令片断是进行日志滚动的基础,用户可以自行编制脚本让cron 执行。下面介绍两种常用的日志滚动配置方法。

  3、使用 rotatelogs 实现日志滚动

  Apache 自带的 rotatelogs 程序可以实现日志滚动。rotatelogs是一个配合 Apache 管道日志功能使用的简单程序。为了使用 rotatelogs 程序,需要在 Apache 配置文件中使用管道日志的配置。

  rotatelogs 命令的格式如图4:

rotatelogs 命令的格式

  rotatelogs 命令的格式

  其中:

  -l:使用本地时间代替GMT时间作为时间基准。

  logfile:日志文件名。有两种格式表示新的日志开始使用的时间。

  如果 logfile中包含”%”,则它会被视为用于strftime()的格式字符串;常用的有:

  %Y:4位数的年份

  %m:2位数的月份

  %d:2位数的一个月中的日期数

  %H:2位数的小时数(24小时制)

  %M:2位数的分钟数

  %S:2位数的秒数

  %U:2位数的一年中的星期数(星期天为一周的第一天)

  %W:2位数的一年中的星期数(星期一为一周的第一天)

  %w:1位数的星期几(星期天为一周的第一天)

  否则它会被自动加上以秒为单位的”.nnnnnnnnnn”后缀,这里 nnnnnnnnnn 是开始记录日志的格林威治时间距离 1970年1月1日 的秒数。

  rotationtime:日志文件滚动的以秒为单位的间隔时间。

  offset:相对于UTC的时差的分钟数。如果省略,则假定为”0″并使用UTC时间。比如,要指定UTC时差为”-5小时”的地区的当地时间,则此参数应为”-300″。

  filesizeM:指定以 filesizeM 文件大小滚动,而不是按照时间来滚动日志。

  使用举例:

  例1:每过一天滚动日志 ,修改apache配置文件如下:
TransferLog “| /opt/coolstack/apache2/bin/rotatelogs / opt/coolstack/apache2/log /access.log 86400” combined
  其中 86400(秒)是日志滚动的时间。86400 秒就是 1 天。滚动以后的文件名为/ opt/coolstack/apache2/log /access.log /access_log.nnnnnnnnnn,这里 nnnnnnnnnn 是开始记录日志的格林威治时间距离 1970年1月1日 的秒数。当日志滚动一次后将生成一个新的日志文件,后缀为前一个日志文件的后缀值加 86400。

  例2:在日志文件大小增长到指定字节时滚动日志 ,修改apache配置文件如下:
TransferLog “|/opt/coolstack/apache2/bin/rotatelogs / opt/coolstack/apache2/log/apache2/access.log 20M” combined
  此配置会在日志文件大小增长到 20M 字节时滚动该日志。

  例3:使用logrotate 实现日志滚动

  logrotate 是Unix、Linux系统实现日志滚动的通用程序。Linux下可以直接使用,Solaris 10 下要进行安装配置。
#wegt ftp://ftp.sunfreeware.com/pub/freeware/intel/10/logrotate-3.7.1-sol10-x86-local.gz
  #gunzip ftp://ftp.sunfreeware.com/pub/freeware/intel/10/logrotate-3.7.1-sol10-x86-local.gz
  #pkgadd –d logrotate-3.7.1-sol10-x86-local
  图5是logrotate安装配置完成界面

logrotate安装配置完成界面

  logrotate安装配置完成界面

  可以把配置文件/usr/local/doc/logrotate/examples/ logrotate-default复制为配置文件/etc/logrotate.conf

  可以把配置文件/usr/local/doc/logrotate/examples/ logrotate.cron复制到文件目录/etc/cron.d/

  下面看看配置文件如图6。

配置文件

  配置文件

  logrotate的配置文件中可以看到,除了wtmp以外,需要滚动的日志的配置都保存在/etc/logroate.d目录下。因此只需要在该目录下创建一个名为apache的配置文件,来指示logrotate如何轮循Web服务器的日志文件即可。下面是一个示例:
/ opt/coolstack/apache2/log {
  rotate 2
  daily
  missingok
  sharedscripts
  postrotate
  /usr/bin/killall -HUP httpd 2> /dev/null || true
  endscript
  }
  这里“rotate 2”表示轮循时只包括两个备份文件,也就是只有access_log、access_log.1和access_log.2三个日志备份文件。这种方法的优点是不需要其它第三方工具就可以实现日志轮循。但是对于重负载的服务器和使用负载均衡技术的Web服务器来说,这种方法不是很实用。因为它是对相应服务进程发出一个-HUP重启命令来实现日志的截断归档的,这样会影响服务的连续性。

  例4:使用使用 cronolog 实现日志滚动

  cronolog (http://cronolog.org/ )是基于 rotatelogs 的一个第三方工具软件。cronolog 可以非常整齐的将日志按天轮循存储,即每个日志文件存储的是 00:00:00 到 23:59:59 时间之内的所有日志。

  1.准备gcc for solaris10 编译器,这里用的版本:gcc-3.3.2-sol10-intel-local.gz

  2.下载解压缩文件
#wegt ftp://ftp.sunfreeware.com/pub/freeware/intel/10/gcc-3.3.2-sol10-intel-local.gz
  #gizip –d gcc-3.3.2-sol10-intel-local.gz
  3.安装 
#pkgadd -d gcc-3.3.2-sol10-intel-local
  接下来的安装,是一个交互安装过程

  默认安装路径/usr/local/bin

  4.设置PATH变量
# PATH=$PATH:/usr/local/bin
  #PATH=$PATH:/usr/ccs/bin
  # export PATH
  5. 准备coronolog,版本:cronolog-1.6.2.tar.gz

  6.下载安装:
#wegt http://cronolog.org/download/cronolog-1.6.2.tar.gz
  # tar zxvf cronolog-1.6.2.tar.gz
  # cd cronolog-1.6.2
  # ./configure
  # make
  # make install
cronolog安装配置完成界面

  cronolog安装配置完成界面

  可以看到默认是安装在/usr/local/sbin/下 。下面是一个使用 cronolog 的例子:
CustomLog “|/usr/local/sbin/cronolog / opt/coolstack/apache2/log /access.log.%Y-%m-%d” combined
  他将按日志依次生成日志文件,如:
access.log.2008-09-18
  access.log.2008-09-19
  access.log.2008-09-20
  access.log.2008-09-21
  access.log.2008-09-22
  若要压缩旧的日志文件或清除无用的日志文件,可以使用 find 等命令 配合系统 crond 来实现。

  总结:到此为止笔者介绍了Solaris 10 web服务器日志配置,本文使用的Apache版本是CoolStack http://cooltools.sunsource.net/coolstack/工具,apache版本2.2.9 。后边笔者会介绍使用PHPMyVisites、apachetop、analog三个工具进行web日志分析。

Apache日志的配置

1、日志类型
  
1.3 版本Apache 的标准中规定了4类日志:
  
错误日志
  
访问日志
  
传输日志
  
Cookie日志
  
其中:传输日志和Cookie日志被Apache 2.0认为已经过时。所以本文仅讨论错误日志和访问日志。同时错误日志和访问日志被Apache 2.0默认设置。
  
错误日志包含:
  
获知失效链接
  
获知 CGI 错误
  
获知用户认证错误
  
访问日志包含:
  
访问服务器的远程机器的地址:可以得知浏览者来自何方
  
浏览者访问的资源:可以得知网站中的哪些部分最受欢迎
  
浏览者的浏览时间:可以从浏览时间(如工作时间或休闲时间)对网站内容进行调整
  
浏览者使用的浏览器:可以根据大多数浏览者使用的浏览器对站点进行优化
  
访问日志分类:
  
为了便于分析 Apache 的访问日志,Apache 的默认配置文件中,按记录的信息不同(用不同格式昵称说明不同的信息)将访问日志分为4类:
  
代理日志格式(agent log format) agent 记录请求的用户代理
  
综合日志格式(combined log format) combined 结合以上三种日志信息
  
普通日志格式(common log format,CLF) common 大多数日志分析软件都支持这种格式
  
参考日志格式(referer log format) referer 记录客户访问站点的用户身份
  
2、配置访问日志命令
  
CustomLog 命令用来对服务器的请求进行日志记录。格式为:
  
格式1:CustomLog 访问日志文件名 记录格式说明串|格式昵称
  
格式2:CustomLog “|管道程序名 访问日志文件名” 记录格式说明串|格式昵称
  
说明:
  
访问日志文件名:除非文件位置用”/“开头,否则所制定的文件位置是相对于 ServerRoot 目录的相对路径
  
格式昵称:使用 LogFormat 命令将一个记录格式说明串赋以一个名称
  
记录格式说明串:用字符串和格式说明符(以%开头)指定日志记录的内容
  
管道程序名:管道符”|”后面紧跟着一个程序的路径,这个程序把日志从标准输入设备中读入并处理。
  
LogFormat 命令用于定义访问日志的记录格式。格式为:
  
LogFormat “记录格式说明串” 格式昵称
  
从apache2.conf 中可知,在Apache 中定义了下面的 4 种类型的访问日志:
LogFormat “%h %l %u %t \”%r\” %>s %b \”%{Referer}i\” \”%{User-Agent}i\”” combined
  LogFormat “%h %l %u %t \”%r\” %>s %b” common
  LogFormat “%{Referer}i -> %U” referer
  LogFormat “%{User-agent}i” agent
由于综合日志格式简单地结合了3种日志信息,所以在配置访问日志时,要么使用一个综合文件进行记录,要么使用分离的多个(1-3)文件记录。通常使用一个综合日志格式文件进行记录,配置为:
CustomLog /var/log/apache2/access.log combined
  若使用3个文件分别进行记录,配置为:
CustomLog /var/log/apache2/access.log common
  CustomLog /var/log/apache2/referer.log referer
  CustomLog /var/log/apache2/agent.log agent
  下面的命令组:
LogFormat “%h %l %u %t \”%r\” %>s %b” common
  CustomLog logs/access_log common
  与下面的命令等效:
CustomLog logs/access_log “%h %l %u %t \”%r\” %>s %b”
  通常我们配置访问日志时,使用先使用 LogFormat 命令定义格式昵称,然后再在 CustomLog 命令中引用昵称的方法。
  在使用 LogFormat 和 CustomLog 命令中为了说明要记录的日志内容,可以使用的常用格式说明符如表-3。
格式说明符
说明
%v
进行服务的服务器的标准名字 ServerName,通常用于虚拟主机的日志记录中。
%h
客户机的 IP 地址。
%l
从identd服务器中获取远程登录名称,基本已废弃。
%u
来自于认证的远程用户。
%t
连接的日期和时间。
%r
HTTP请求的首行信息,典型格式是“METHOD RESOURCE PROTOCOL”,即“方法 资源 协议”。经常可能出现的 METHOD 是 GET、POST 和 HEAD;RESOURCE 是指浏览者向服务器请求的文档或 URL;PROTOCOL 通常是HTTP,后面再加上版本号,通常是 HTTP/1.1。
%>s
响应请求的状态代码,一般这项的值是 200,表示服务器已经成功地响应浏览器的请求,一切正常;以 3 开头的状态代码表示由于各种不同的原因用户请求被重定向到了其他位置;以 4 开头的状态代码表示客户端存在某种错误;以 5 开头的状态代码表示服务器遇到了某个错误。
%b
传送的字节数(不包含HTTP头信息),将日志记录中的这些值加起来就可以得知服务器在一天、一周或者一月内发送了多少数据。
%{Referer}i
记录引用此资源的网页。
%U
请求的URL路径,不包含查询串。
  图2是从一个访问日志文件中截取的几条记录。这里使用winscp远程登录到Solaris 10 服务器的日志文件目录。

apache 访问日志

 图2 apache 访问日志
  
将其中一列各项信息分离于表-4所示。

格式说明符

举例1
%h
远程主机IP
192.168.220.1
%l

-(表示没有取得信息)
%u


%t
访问日期,时间和时差

14/Oct/2008:19:54:51 +0800
%r
请求 / 版本
“GET / HTTP/1.1”
%>s
服务状态码
404
%b
发送的字节数
1185
%{Referer}i

”-”
%{User-Agent}i

  3、配置错误日志

  错误日志记录了服务器运行期间遇到的各种错误,以及一些普通的诊断信息,比如服务器何时启动、何时关闭等。

  ErrorLog 命令指定了当服务器遇到错误时记录错误日志的文件名。其格式为:

  格式1:ErrorLog 错误日志文件名

  格式2:ErrorLog “|管道程序名”

  格式1直接指定错误日志文件名,除非文件位置用”/“开头,否则 ErrorLog 所制定的文件位置是相对于 ServerRoot 目录的相对路径。

  格式2实现管道日志,它指定一个命令来处理错误日志。

  Apache 编译时默认的错误日志可以使用如下命令获得:
$ apache2 -V| grep DEFAULT_ERRORLOG
  -D DEFAULT_ERRORLOG=”logs/error_log”
  LogLevel

  LogLevel 用于调整记于错误日志中的信息的详细程度。
等级
应用说明
级别
emerg
出现紧急情况使得该系统不可用,如系统宕机等
1
alert
需要立即引起注意的情况
2
crit
危险情况的警告
3
error
除了emerg、alert、crit的其他错误
4
warn
警告信息
5
notice
需要引起注意的情况,但不如error、warn重要
6
info
值得报告的一般消息
7
debug
由运行于debug模式的程序所产生的消息
8
  图3是从一个访问错误文件中截取的几条记录。这里使用winscp远程登录到Solaris 10 服务器的日志文件目录。

apache 错误日志

  图3 apache 错误日志

  从文件内容可以看出,每一行记录了一个错误。格式为:

  日期和时间 错误等级 错误消息

referer

由于项目需要,我接触到了javascript中的referer. 在网上找资料的时候,发现有这两篇文章对referer写得蛮好的,现把它们转贴到下面,一起学习.

第1篇–(http://huxiong888.blog.163.com/blog/static/1344952201061501535775/)

Referrer的重要性

HTTP请求中有一个referer的报文头,用来指明当前流量的来源参考页。例如在www.sina.com.cn/sports/上点击一个链接到达cctv.com首页,那么就referrer就是www.sina.com.cn/sports/了。在Javascript中,我们可以通过 document.referrer来获取同样的信息。通过这个信息,我们就可以知道访客是从什么渠道来到当前页面的。这对于Web Analytics来说,是非常重要的,这可以告诉我们不同渠道带来的流量的分布情况,还有用户搜索的关键词等,都是通过分析这个referrer信息来获取的。

但是,出于各种各样的原因,有时候Javascript中读到的referrer却是空字符串。下面总结一下哪些情况下会丢失referrer。

Referrer丢失的几个场景
修改Location对象进行页面导航
Location对象是一个用于页面导航的非常实用的对象。因为他允许你只变更Url的其中一部分。例如从cn域名切换到com域名,其他部分不变:

window.location.hostname = “example.com”;
但是,通过修改Location进行页面导航的方法,会导致在IE下丢失Referrer。

IE5.5+ 下返回空字符串

Chrome3.0+,Firefox3.5,Opera9.6,Safari3.2.2均正常返回来源网页

window.open方式打开新窗口
示例:

访问Google
点击此链接会在新窗口打开Google网站,我们在地址栏中输入以下js代码就可以看到发送的referrer了。

javascript:alert(document.referrer)
测试结果:

IE5.5+ 下返回空字符串

Chrome3.0+,Firefox3.5,Opera9.6,Safari3.2.2均正常返回来源网页

如果是同个域名下通过此方式跳转的,那么我们可以通过访问windoww.opener对象去获取丢失的referrer信息。代码如下:


跨域的话则没辙了~

鼠标拖拽打开新窗口
鼠标拖拽是现在非常流行的用户习惯,很多浏览器都内置或者可以通过插件的方式来支持鼠标拖拽式浏览。但是通过这种方式打开的页面,基本全都丢失 referrer。并且,这种情况下,也无法使用window.opener的方式去获取丢失的referrer了。

已测试:

Maxthon2.5.2,Firefox的FireGesture插件,Chrome3.0+,Opera9.6,Safari3.2。

点击Flash内部链接
点击Flash上到达另外一个网站的时候,Referrer的情况就比较杂乱了。

IE下,通过客户端Javascript的document.referrer读取到的值是空的,但是如果你使用流量监控软件看一下的话,你会发现,实际上HTTP请求中的Referer报文头却是有值的,这可能是IE实现的Bug。同时,这个值指向的是Flash文件的地址,而不是来源网页的地址。

Chrome4.0下点击Flash到达新窗口之后,Referrer也是指向的Flash文件的地址,而不是源网页的地址。

Chrome3.0和Safari3.2是一样的,都是会丢失Referrer信息。

Opera则和Firefox一样,Referrer的值都是来源网页的地址。

HTTPS跳转到HTTP
从HTTPS的网站跳转到HTTP的网站时,浏览器是不会发送referrer的。这个各大浏览器的行为是一样的。

例如,我们在HTTPS下使用Google Reader或是Gmail的时候,点击某个链接去到另外一个网站,那么从技术上来说,这样的访问和用户直接键入网址访问是没有什么分别的。

Referrer丢失对于广告流量监控的影响
Referrer如果丢失,Web Analytics就会丢掉很重要的一部分信息了,特别对于广告流量来说,就无法知道实际来源了。目前国内好多用了Google Adsense广告的网站,都使用了window.open的方式来打开广告链接,因此IE下会丢失Referrer,而我们知道,IE是目前市场份额最大的浏览器,因此其影响是很大的。很多流量统计工具会因此将这部分流量归入“直接流量”,和用户直接键入网址等价了。

对于这样的情况,需要让广告投放者在投放广告的时候,给着陆页面的Url加上特定的跟踪参数。

例如,某个Flash广告,点击之后到达的网址是http://www.example.com/,为了监控此流量是从哪个渠道过来的,我们可以修改此投放的着陆Url,改成http://www.example.com/?src=sina,类似这种方式,然后在着陆页面中使用 Javascript代码提取此src参数,这样就可以得到广告来源信息。

在投放Google Adwords的时候,后台系统有一个“自动标记”的选项,当启用此选项的时候,Google在生成所有广告的着陆页面Url的时候,就会自动加上一个 gclid的参数,这个参数能够将Google Analytics后台和Adwords广告后台的数据进行整合。这样就可以知道广告流量对应于哪个广告系列,哪个广告来源和广告关键词等信息了。和上面提到的思路其实是类似的。只不过Google自动帮你做了Url的修改了而已。

第二篇–(http://blog.163.com/alex_kame/blog/static/14546748201072173718721/)

兼容IE和FF:获取Referer的JS方法

发现一个关于浏览器兼容的问题,当用JS 执行代码 window.location.href=”http://ityizhan.com” 来进行跳转的时候,Firefox 可以获取到到HTTP_REFERER页面,但是在IE中这一项为空,后来查了一些相关资料,发现在IE 中通过 window.location.href 或者是 是无法获取HTTP_REFERER, 真是搞不懂 IE 的浏览器,很多浏览器运行的很好的东西,它就是不支持,最后没有办法,只能PHP伪造来源HTTP_REFERER的方法或者用JS来伪造。
IE可以识别的 HTTP_REFERER 提交是通过click 触发的事件或者是 Form 表单提交的请求,下面是根据网上的资料总结的一个方法:

这个方法先是用 document.all 来判断当前的浏览器是否是IE, 如果是的话就生成一个link,然后自动执行 onclick 事件,如果不是的话就用JS 跳转。这样在处理页面就可以得到 HTTP_REFERER 了

此方法在IE, Firefox, Safari , Chrome 测试通过

各搜索引擎referer关键字,编码

在做商务E流量分析的时候,需要实现一个功能:如果访客是通过搜索引擎的搜索找到客户网站的,要统计出访客是通过哪个搜索引擎访问到页面,并且统计出是通过 什么关键字搜索到该网站的。在网上google一下,发出对这方面的描述文档还是比较少的,在做这个功能的过程中有些经验给人家分享一下。

实现这样的功能,基本原理是获取到来源地址,然后分析其中的内容,把所需要的搜索引擎名称和关键字取出。
获取来源地址很简单,在servlet 中可以通过HttpServletRequest.getHeader(“Referer”)方法取得,jsp页面中可以通过 request.getHeader(“referer”)取得。取得来源地址后便可以通过分析得到的来源地址分析出我们所需要的内容。通常我们常用的搜 索引擎有以下14个。
http://www.google.com;
http://www.google.cn;
http://www.sogou.com;
http://so.163.com;
http://www.iask.com;
http://www.yahoo.com;
http://www.baidu.com;
http://www.3721.com;
http://www.soso.com;
http://www.zhongsou.com;
http://www.alexa.com;
http://www.search.com;
http://www.lycos.com;
http://www.aol.com;

要获取我们所需要的内容,我们必须分析 各个引擎的特性,由于各个搜索引擎的格式不一样,获取到的来源地址必然也不一致,下面我们来分析一下各种搜索引擎的地址格式。

在搜索引擎里输入关键字,点击搜索之后地址栏中的内容就是我们通过HttpServletRequest.getHeader(“Referer”)或 request.getHeader(“referer”)取得的来源地址。

google搜索引擎:
http://www.google.com/search?hl= zh-N&newwindow=1&
q=%E4%BB%8A%E7%A7%91%E4%BF%A1%E6%81%AF%E7%A7%91%E6%8A%80&
btnG= %E6%90%9C%E7%B4%A2&lr=

http://www.google.cn/search?hl= zh-N&newwindow=1&
q=%E6%B0%B8%E5%AE%89%E8%B7%AF%E7%81%AF&
btnG= %E6%90%9C%E7%B4%A2&meta=

从这里我们可以得到我们所需要的搜索引擎名称和关键字。其中,搜索引擎显而易见,是google;而关键字呢?经过我仔细观察、
测试后发现关键字是编码后放 在参数q里,也就是说
%E4%BB%8A%E7%A7%91%E4%BF%A1%E6%81%AF%E7%A7%91%E6%8A%80和
%E6%B0 %B8%E5%AE%89%E8%B7%AF%E7%81%AF
就是输入的关键字。

(有人会问,那btnG这个参数的值是什么来头,他也编过码 啊?是用来干嘛的呢?呵呵,它什么来头都没有,什么也没干,多余的!你试试输入关键字之后点击搜索按钮看看地址栏,然后再试试输入关键字之后回车,再看看 地址栏,看出两种做法在地址栏中的一点点差别之后你就会明白的啦)

baidu搜索引擎:
(1)http://www.baidu.com/s?ie=gb2312&bs=%CB%B3%B5%C2%BC%D2%BE%DF&sr=&z=&cl=3&f=8&
wd=%BD%F1%BF%C6%BF%C6%BC%BC&ct=0
(2)http://www.baidu.com/baidu?tn=nanlingcb&word=%CB%B3%B5%C2%BC%D2%BE%DF

baidu 搜索引擎,这里需要说明一下,当我们在通过在http://www.baidu.com中 输入搜索关键字,获取的来源地址为(1)字符串;当通过其它方式,比如在一些浏览器插件中输入关键字搜索的获取的来源地址为(2)字符串。通过获取来的这来源地,我也可以很容易的知道当前的搜索引擎是baidu;而关键字呢?看看(1),这里有两个经过编码的字符串,到底哪个是关键字呢?wd的值是关键字!信我啦!那bs的值是什么呢?你输入关键字多搜索几次,看看你有什么发现?发现了吧,bs是你上一次搜索的关键字!这个我们不管,它不是我们所要的东 西。分析得知,在baidu搜索引擎里有两个地方放关键字,一个地方是编码后放在在参数wd里,另外一个地方是编码后放在word参数里。明白了吧?:)

sogou搜索引擎
http://www.sogou.com/web?query=%BD%F1%BF%C6%D0%C5%CF%A2%BF%C6%BC%BC
这个就没这么复杂了,我们通过字符串可以知道搜索引擎为sogou,关键字经编码后放在参数query里,这里值为
%BD%F1%BF%C6%D0%C5 %CF%A2%BF%C6%BC%BC,有时候也会附带多一些参数,但附带的这些参数对我们来说是没用的。

163搜索引擎
http://cha.so.163.com/so.php?in=seek&c=26&key=032152284&q=%BD%F1%BF%C6%D0%C5%CF%A2%BF%C6%BC%BC
&x=61&y=19
这个也不复杂,分析得知,搜索引擎名称为163,关键字在参数q里,这里值为%BD%F1%BF%C6%D0%C5%CF%A2%BF%C6%BC%BC

yahoo 搜索引擎
http://search.cn.yahoo.com/search?p=%D3%C0%B0%B2%C2%B7%B5%C6&
source=toolbar_yassist_button&pid=58061_1006&ei=gbk

http://search.cn.yahoo.com/search?lp=%E4%B8%AD%E5%B1%B1%E5%8F%A4%E9%95%87%E7%81%AF%E9%A5%B0&
p=%E4%BB%8A%E7%A7%91%E4%BF%A1%E6%81%AF%E7%A7%91%E6%8A%80&pid=&ei=UTF-8
很容易得到,搜索引擎名称为yahoo,那关键字是哪些呢?关键字是放在参数p里,而参数lp的值跟baidu类似,也是上一次搜索的关键字。

lycos 搜索引擎
http://search.lycos.com/?query=website
这 个我们用得比较少,同样我们通过这个字符串得出搜索引擎为lycos,关键字放在query里.

3721搜索引擎
http://seek.3721.com/index.htm?name=%D6%E9%BA%A3%CF%E3%D6%DE%C0%CD%CE%F1%CA%D0%B3%A1
容 易得到,搜索引擎名称为3721,关键字放在name里

search搜索引擎
http://www.search.com/search?lq=d%25E4%25B8%25AD%25E5%259B%25BDd&
q=%E4%B8%AD%E5%8D%8E%E4%BA%BA%E6%B0%91%E5%85%B1%E5%9B%BD%E5%92%8C
这 个我们用得很少,也容易得到搜索引擎名称为search,关键字放在p里,而lp放的是什么呢?尚未弄清楚,
反正与我们所要的东西无关。

soso 搜索引擎
http://www.soso.com/q?w=%BD%F1%BF%C6%D0%C5%CF%A2%BF%C6%BC%BC12&sc=web&
bs=%BD%F1%BF%C6%D0%C5%CF%A2%BF%C6%BC%BC1&ch=w.soso.pr&uin=&lr=chs&web_options=on
可 以看出搜索引擎名称为soso,关键字放在参数w里,需参数bs的值跟baidu相似,是上一次搜索的关键字
zhongsou搜索引擎
http://p.zhongsou.com/p?w=%BD%F1%BF%C6%D0%C5%CF%A2%BF%C6%BC%BC&l=&jk=&k=&r=&aid=&pt=1&dt=2
可 以看出搜索引擎名称为zhongsou,关键字在参数w里。

alexa搜索引擎
http://www.alexa.com/search?q=%E4%BB%8A%E7%A7%91%E4%BF%A1%E6%81%AF%E7%A7%91%E6%8A%80
得出搜索引擎名称为zhongsou,关键字放在参数q里。
对各种搜索引擎的url的分析已完成,大家都对这些常用的搜索引擎的url的格式有所了解了,下面我们看看怎样从我们所取得的这些字符串中得到我们所要的信息,也就是怎样从这些字符串中提取我们所需的搜索引擎名称和搜索关键字.这里理所当然使用功能强大的正则表达式了.好,现在我们逐个逐个地分析各个搜索引擎用什么正则表达式提取我们所需要的内容.
首先还是先分析 google搜索引擎:
上面已经提到我们取得的google搜索引擎的地址是这样的:
http://www.google.com/search?hl= zh-N&newwindow=1
&q=%E4%BB%8A%E7%A7%91%E4%BF%A1%E6%81%AF%E7%A7%91%E6%8A%80&
btnG= %E6%90%9C%E7%B4%A2&lr=

http://www.google.cn/search?hl= zh-N&newwindow=1
&q=%E6%B0%B8%E5%AE%89%E8%B7%AF%E7%81%AF&
btnG= %E6%90%9C%E7%B4%A2&meta=

其 实它还有一种形式是这样的:
(3)http://www.google.com/custom?hl=zh-CN&inlang=zh-CN&ie=GB2312&oe=GB2312&newwindow=1&
client=pub3261928361684765&cof=FORID%3A1%3BGL%3A1%3BBGC%3AFFFFFF%3BT%3A%23000000%3BLC%3A
%230000ff%3BVLC%3A%23663399%3BALC%3A%230000ff%3BGALT%3A%23008000%3BGFNT%3A
%230000ff%3BGIMP%3A%230000ff%3BDIV%3A%23336699%3BLBGC%3A336699%3BAH%3Acenter%3B
&q=%C5%B7%C2%FC%D5%D5%C3%F7&lr=
OH,my god,是不是看得头晕了?先不要晕,往下看你就不会觉得晕的啦….

我们仔细观察一下,这三种格式都有一个共通点,大家有没有发现呢?就是 他的格式都是这样的:

http://www.google.[…]/[…]&q= [关键字][…]
[…]表示有一个以上的字符.

就如(2)我们在里面放入一些[]就可以看得更清楚了:
http://www.google.[cn]/[search?hl=zh-CN&newwindow=1]
&q=[%E6%B0%B8%E5%AE%89%E8%B7%AF%E7%81%AF][&btnG=%E6%90%9C%E7%B4%A2&meta=]
看明白了吧?看明白了我们就接下去了.于是我们可以得出google搜索引擎的正则表达式了:

http:\\/\\/www\\.google \\.[a-zA-Z]+\\/.+[\\&\\?]q=[^\\&]*。

现在解释一下这个正则表达式的意思。
http:\\/ \\/www\\.这一段是匹配http://www.,为什么这里多了这么多\呢?因为字符 ‘/’和字符’.’在正则表达式中有特殊意义,要用’\’对这两个字符转义,’/’通过’\/’转义,相似的.也通过’\.’转义,而字符’\’在 java里也是一个特殊字符,本身也需要转义,所以’\/’写成’\\/’,类似的’\.’写成’\\.’;

接下来google\\.[a-zA-Z]+ \\/.+匹配google.com/search?hl=zh-CN&newwindow=1,这里解释一下[a-zA-Z]+,意思是最少有 一个(包括一个)以上英文字母,[a-zA-Z]表示从a到z,从A到Z的字符,+表示至少一个以上,[\\&\\?]q=[^\\&]*匹配的是&q=%E6%B0%B8%E5%AE%89%E8%B7%AF%E7%81%AF,[\\&\\?],表示字符&或字符?由于&和?都是特殊字符,所以都要用转义符转义,q=[^\\&]*表示q=后面是零个(包括零个)以上的非& 字符,[^\\&]表示不为&的字符,为什么不为&呢,因为&后面的字符也经不再属于参数q的值了,我们要取的是q=之 后,字符&之前的字符串.这个正则表达式的解释就到此了。现在这个正则表达式已经可以从众多的获取过来的来源地址中分辩出哪些是google搜索引擎了,但是有一个问题,假如以后google搜索引擎不是这样,换成http://search.google.com/search?hl=zh-CN&newwindow=1&q=%E6%B0%B8%E5%AE%89%E8%B7%AF%E7%81%AF
&btnG=%E6%90%9C%E7%B4%A2&meta= 呢,

那这个正则表达式就不合适了,怎样能在以后改动之后我们写的正则表达式还适用呢?很简单,我们把它改成这个样子:\\.google\\.[a- zA-Z]+\\/.+[\\&\\?]q=[^\\&]*,意思是我们不必匹配http://www这 一串字符串。这样如果google搜索引擎做了类似http://search.google.com/….. 的修改,我们写的正则表达式也适用了,那假如它把域名也改了就没得说了,:);还有一种情况,在地址栏里输入www.google.com:80/也可以正常访问google,也就是说还有 一种情况就是加端口的访问,这种情况也要考虑到,因此之前我们的正则表达式应改成:\\.google\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]q=[^\\&]*, (:\\d{1,}){0,1}是什么意思呢?他匹配类似”:80″也就是说冒号(:)后跟1个以上的数字字符,而端口是可选的,并且如果出现只会出现一 次,所以用{0,1}.这个正则表达式的用途是用于获取关键字,所以这里我把关键字部分划分为一个组(这在下面会用到),因此,最终的正则表达式为:

\\.google\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]q=([^\\&]*)

对 google搜索引擎已经说得很详细,接下来的我就简略的说说了,原理都差不多的了。

baidu搜索引擎:
分 析得知baidu搜索引擎的正则表达式为:
\\.baidu\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]wd=([^\\&]*) 或
\\.baidu\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]word=([^\\&]*)

sogou 搜索引擎
http://www.sogou.com/web?query=%BD%F1%BF%C6%D0%C5%CF%A2%BF%C6%BC%BC
正 则表达式:
\\.sogou\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]query=([^\\&]*)
yahoo搜索引擎
正 则表达式:
\\.yahoo\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]p=([^\\&]*)

lycos 搜索引擎
http://search.lycos.com/?query=website
正 则表达式:
\\.lycos\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.*[\\&\\?]query=([^\\&]*)

3721 搜索引擎
http://seek.3721.com/index.htm?name=%D6%E9%BA%A3%CF%E3%D6%DE%C0%CD%CE%F1%CA%D0%B3%A1
http://seek.3721.com/index.htm?q=%D6%E9%BA%A3%CF%E3%D6%DE%C0%CD%CE%F1%CA%D0%B3%A1
正 则表达式:
\\.3721\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]p=([^\\&]*) 或
\\.3721\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]name=([^\\&]*)

search 搜索引擎
正则表达式:
\\.search\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]q=([^\\&]*)
soso搜索引擎
正 则表达式:
\\.soso\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]w=([^\\&]*)
zhongsou搜索引擎
http://p.zhongsou.com/p?w=%BD%F1%BF%C6%D0%C5%CF%A2%BF%C6%BC%BC&l=&jk=&k=&r=&aid=&pt=1&dt=2
正 则表达式:
\\.zhongsou\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]w=([^\\&]*)
alexa搜索引擎
http://www.alexa.com/search?q=%E4%BB%8A%E7%A7%91%E4%BF%A1%E6%81%AF%E7%A7%91%E6%8A%80
正 则表达式:
\\.alexa\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]q=([^\\&]*)
iask搜索引擎
正则表达式:
\\.iask\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]k=([^\\&]*) 或
\\.iask\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]_searchkey=([^\\&]*)

好了,正则表达式已经写出来了,事情已经完成一半了。现在我们把话题转一下,等会我们再转回来,现在我们先看看如何获取搜索引擎的名称。同样,也 需要用正则表达式,正则表达式实在太强了:)。
我们可以通过以下的正则表达式匹配到google搜索引擎:
http:\\/\\/.* \\.google\\.com(:\\d{1,}){0,1}\\/或
http:\\/\\/.*\\.google\\.cn(:\\d{1,}){0,1}\\/

类 似的也可以匹配其它搜索引擎,我把他们写在一起:
http:\\/\\/.*\\.(google\\.com(:\\d{1,}){0,1}\\/|google\\.cn(:\\d{1,}){0,1}\\/|
baidu\\.com(:\\d{1,}){0,1}\\/|yahoo\\.com(:\\d{1,}){0,1}\\/|
iask\\.com(:\\d{1,}){0,1}\\/|sogou\\.com(:\\d{1,}){0,1}\\/|
163\\.com(:\\d{1,}){0,1}\\/|lycos\\.com(:\\d{1,}){0,1}\\/|
aol\\.com(:\\d{1,}){0,1}\\/|3721\\.com(:\\d{1,}){0,1}\\/|
search\\.com(:\\d{1,}){0,1}\\/|soso.com(:\\d{1,}){0,1}\\/|
zhongsou\\.com(:\\d{1,}){0,1}\\/|alexa\\.com(:\\d{1,}){0,1}\\/)
通过以下程序可以获取到搜索引擎的名称:
import java.util.regex.*;
public class GetEngine
{
public static void main(String[] arg)
{
GetEngine engine=new GetEngine();

String referer=”http://www.baidu.com/s?wd=java%D1%A7%CF%B0%CA%D2″;
String engineName=engine.getSearchEngine(referer);
System.out.println(“搜索引擎名称:”+engineName);
}
public String getSearchEngine(String refUrl) {
if(refUrl.length()>11)
{
//p是匹配各种搜索引擎的正则表达式
Pattern p = Pattern.compile(“http:\\/\\/.*\\.(google\\.com(:\\d{1,}){0,1}\\/|
google\\.cn(:\\d{1,}){0,1}\\/|baidu\\.com(:\\d{1,}){0,1}\\/|
yahoo\\.com(:\\d{1,}){0,1}\\/|iask\\.com(:\\d{1,}){0,1}\\/|
sogou\\.com(:\\d{1,}){0,1}\\/|163\\.com(:\\d{1,}){0,1}\\/|
lycos\\.com(:\\d{1,}){0,1}\\/|aol\\.com(:\\d{1,}){0,1}\\/|
3721\\.com(:\\d{1,}){0,1}\\/|search\\.com(:\\d{1,}){0,1}\\/|
soso.com(:\\d{1,}){0,1}\\/|zhongsou\\.com(:\\d{1,}){0,1}\\/|
alexa\\.com(:\\d{1,}){0,1}\\/)”);
Matcher m = p.matcher(refUrl);
if (m.find())//如果来源地址可以匹配以上的pattern
{
//因为m.group(0)是域名,m.group(1)才是我们最合适我们所要的
return insteadCode(m.group(1),”(\\.com(:\\d{1,}){0,1}\\/|\\.cn(:\\d{1,}){0,1}\\/|
\\.org(:\\d{1,}){0,1}\\/)”,””);//把.com,.cn,.org替换为””
}
}
return “未发现搜索引擎”;
}
public String insteadCode(String str,String regEx,String code){
Pattern p=Pattern.compile(regEx);
Matcher m=p.matcher(str);
String s=m.replaceAll(code);
return s;
}
}

通过以上的代码即可得出搜索引擎名称了,似乎任务完成一大半了。只是接着下来的要做的事情比之前所做的要麻烦点点,麻烦就麻烦在编码上。
现在我样回过头看我们上面写的一大堆各种搜索引擎的正则表达式。
由于这里要大量的字符串操作,这里使用StringBuffer来做字符串的连接。
StringBuffer sb=new StringBuffer();
sb.append(“\\.google\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]q=([^\\&]*)”)
.append(“|\\.iask\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]k=([^\\&]*)”)
.append(“|\\.iask\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]_searchkey=([^\\&]*)”)
.append(“|\\.sogou\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]query=([^\\&]*)”)
.append(“|\\.163\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]q=([^\\&]*)”)
.append(“|\\.yahoo\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]p=([^\\&]*)”)
.append(“|\\.baidu\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]wd=([^\\&]*)”)
.append(“|\\.baidu\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]word=([^\\&]*)”)
.append(“|\\.lycos\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.*[\\&\\?]query=([^\\&]*)”)
.append(“|\\.aol\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]encquery=([^\\&]*)”)
.append(“|\\.3721\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]p=([^\\&]*)”)
.append(“|\\.3721\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]name=([^\\&]*)”)
.append(“|\\.search\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]q=([^\\&]*)”)
.append(“|\\.soso\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]w=([^\\&]*)”)
.append(“|\\.zhongsou\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]w=([^\\&]*)”)
.append(“|\\.alexa\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]q=([^\\&]*)”);
这个正则表达式是把所有搜索引擎用或”|”连接起来,因为只要匹配其中一个搜索引擎的正则表达式就可以。
前面已经说到,关键字是经过编码 的,我们直接取出的关键字会像%BD%F1%BF%C6%D0%C5%CF%A2%BF%C6%BC%BC12,
这样的关键字我们无法读懂,因些需要对这 些关键进行反编码,这要用到java.net.URLDecoder.decode(String s,String enc),这个方法有两个参数,一个参数是要进行反编码的字符串,另一个是指定的字符集。第一个参数很简单,只要我们把取得的关键放到这个参数里,至于第 二个参数怎样呢?这里我只讨论中文的情况,这些搜索引擎有两种字符集编码方式,一种是UTF-8,另外一种是GBK。
只有GBK一种编码方式的搜 索引擎:
3721,iask,sogou,163,baidu,soso,zhongsou
只有UTF-8一种编码方式的搜索引擎:
lycos,aol,search,alexa
有 两种编码方式的:
google,yahoo
只有一种编码方式的问题容易解决,有两种编码方式的怎办呢?办法总比问题多,其实采用哪一个编码方工,它是有”暗示“的,对于google,大多数情况下它是采用UTF-8的编码方式,我们在浏览器的地址栏上输入www.google.com搜索的都是以这种方式来编码的,但有种情况如:
http://www.google.com/custom?hl=zh-CN&inlang=zh-CN&ie=GB2312&oe=GB2312&newwindow=1&client=pub-3261928361684765&
cof=FORID%3A1%3BGL%3A1%3BBGC%3AFFFFFF%3BT%3A%23000000%3BLC%3A%230000ff
%3BVLC%3A%23663399%3BALC%3A%230000ff%3BGALT%3A%23008000%3BGFNT%3A%230000ff%3BGIMP%3A
%230000ff%3BDIV%3A%23336699%3BLBGC%3A336699%3BAH%3Acenter%3B&q=%C5%B7%C2%FC%D5%D5%C3%F7&lr=

这种情况下就不一定是UTF-8编码了,这种情况下以ie这个参数指定,这里ie=gb2312,所以编码方式为gb2312,而gb2312是gbk的字 集,所以这里我们用gbk而不用gb2312;对于yahoo情况类似,只不过yahoo在大多数情况下使用GBK编码,如:
http://search.cn.yahoo.com/search?p=%C5%B7%C2%FC%BF%C6%BC%BC%CA%B5%D2%B5
&source=toolbar_yassist_button&pid=54554_1006&f=A279_1
就是GBK编码,但这种情况:
http://search.cn.yahoo.com/search?ei=gbk&fr=fp-tab-web-ycn&source=errhint_up_web
&p=%BD%F1%BF%C6&meta=vl%3Dlang_zh-CN%26vl%3Dlang_zh-TW&pid=ysearch
就 用ei参数里指定的纺码方式了,这里有可能指定的是gbk,也有可能指定的是UTF-8。
根据以上的解释,于是有以下的程序来获得各种搜索引擎的关键字:

//Java代码
[code]
package com.mytophome.framework;

import java.util.regex.*;
import java.net.URLDecoder;
import java.io.*;

public class GetKeyword {
public static void main(String[] arg) {
String referer = "http://www.baidu.com/s?wd=java%D1%A7%CF%B0%CA%D2";
if (arg.length != 0) {
referer = arg[0];
}
GetKeyword getKeyword = new GetKeyword();
String searchEngine = getKeyword.getSearchEngine(referer);
System.out.println("searchEngine:" + searchEngine);
System.out.println("keyword:" + getKeyword.getKeyword(referer));
}

public String getKeyword(String refererUrl) {
StringBuffer sb = new StringBuffer();
if (refererUrl != null) {
sb.append("(google\\.[a-zA-Z]+/.+[\\&|\\?]q=([^\\&]*)")
.append("|iask\\.[a-zA-Z]+/.+[\\&|\\?]k=([^\\&]*)")
.append("|iask\\.[a-zA-Z]+/.+[\\&|\\?]_searchkey=([^\\&]*)")
.append("|sogou\\.[a-zA-Z]+/.+[\\&|\\?]query=([^\\&]*)")
.append("|163\\.[a-zA-Z]+/.+[\\&|\\?]q=([^\\&]*)")
.append("|yahoo\\.[a-zA-Z]+/.+[\\&|\\?]p=([^\\&]*)")
.append("|baidu\\.[a-zA-Z]+/.+[\\&|\\?]wd=([^\\&]*)")
.append("|baidu\\.[a-zA-Z]+/.+[\\&|\\?]word=([^\\&]*)")
.append("|lycos\\.[a-zA-Z]+/.*[\\&|\\?]query=([^\\&]*)")
.append("|aol\\.[a-zA-Z]+/.+[\\&|\\?]encquery=([^\\&]*)")
.append("|3721\\.[a-zA-Z]+/.+[\\&|\\?]p=([^\\&]*)")
.append("|3721\\.[a-zA-Z]+/.+[\\&|\\?]name=([^\\&]*)")
.append("|search\\.[a-zA-Z]+/.+[\\&|\\?]q=([^\\&]*)")
.append("|soso\\.[a-zA-Z]+/.+[\\&|\\?]w=([^\\&]*)")
.append("|zhongsou\\.[a-zA-Z]+/.+[\\&|\\?]w=([^\\&]*)")
.append("|alexa\\.[a-zA-Z]+/.+[\\&|\\?]q=([^\\&]*)")
.append(")");
Pattern p = Pattern.compile(sb.toString());
Matcher m = p.matcher(refererUrl);
return decoderKeyword(m, refererUrl);
}
return null;
}

/**
* 添加了百度搜索引擎的编码问题
* @param m
* @param refererUrl
* @return
*/
public String decoderKeyword(Matcher m, String refererUrl) {
String keyword = null;
String encode = "UTF-8";
String searchEngine = getSearchEngine(refererUrl);
if (searchEngine != null) {
if ((checkCode("3721|iask|sogou|163|soso|zhongsou", searchEngine)
|| (checkCode("yahoo", searchEngine) && !checkCode("ei=utf-8",refererUrl.toLowerCase())))
|| (checkCode("baidu", searchEngine) && !checkCode("ie=utf-8", refererUrl.toLowerCase()))) {
encode = "GBK";
}

if (m.find()) {
for (int i = 2; i <= m.groupCount(); i++) {
if (m.group(i) != null)// 在这里对关键字分组就用到了
{
try {
keyword = URLDecoder.decode(m.group(i), encode);
} catch (UnsupportedEncodingException e) {
System.out.println(e.getMessage());
}
break;
}
}
}
}
return keyword;
}

public String getSearchEngine(String refUrl) {
if (refUrl.length() > 11) {
// p是匹配各种搜索引擎的正则表达式
// p是匹配各种搜索引擎的正则表达式
Pattern p = Pattern
.compile("http:\\/\\/.*\\.(google\\.com(:\\d{1,}){0,1}\\/"
+ "|google\\.cn(:\\d{1,}){0,1}\\/"
+ "|baidu\\.com(:\\d{1,}){0,1}\\/"
+ "|yahoo\\.com(:\\d{1,}){0,1}\\/"
+ "|iask\\.com(:\\d{1,}){0,1}\\/"
+ "|sogou\\.com(:\\d{1,}){0,1}\\/"
+ "|163\\.com(:\\d{1,}){0,1}\\/"
+ "|lycos\\.com(:\\d{1,}){0,1}\\/"
+ "|aol\\.com(:\\d{1,}){0,1}\\/"
+ "|3721\\.com(:\\d{1,}){0,1}\\/"
+ "|search\\.com(:\\d{1,}){0,1}\\/"
+ "|soso.com(:\\d{1,}){0,1}\\/"
+ "|zhongsou\\.com(:\\d{1,}){0,1}\\/"
+ "|alexa\\.com(:\\d{1,}){0,1}\\/)");
Matcher m = p.matcher(refUrl);
if (m.find()) {
return insteadCode(m.group(1),"(\\.com(:\\d{1,}){0,1}\\/|\\.cn(:\\d{1,}){0,1}\\/|\\.org(:\\d{1,}){0,1}\\/)","");
}
}
return "未发现有搜索引擎";
}

public String insteadCode(String str, String regEx, String code) {
Pattern p = Pattern.compile(regEx);
Matcher m = p.matcher(str);
String s = m.replaceAll(code);
return s;
}

public boolean checkCode(String regEx, String str) {
Pattern p = Pattern.compile(regEx);
Matcher m = p.matcher(str);
return m.find();
} }[/code]

分析网站原始访问日志

想要知道什么人在什么时候浏览了网站的哪些内容吗?查看Apache的访问日志就可以知道。访问日志是Apache的标准日志,本文详细解释了访问日志的内容以及相关选项的配置。

一、访问日志的格式

   Apache内建了记录服务器活动的功能,这就是它的日志功能。这个《Apache日志》系列文章介绍的就是Apache的访问日志、错误日志,以及如何分析日志数据,如何定制Apache日志,如何从日志数据生成统计报表等内容。

   如果Apache的安装方式是默认安装,服务器一运行就会有两个日志文件生成。这两个文件是access_log(在Windows上是access.log)和error_log(在Windows上是error.log)。采用默认安装方式时,这些文件可以在/usr/local/apache/logs下找到;对于Windows系统,这些日志文件将保存在Apache安装目录的logs子目录。不同的包管理器会把日志文件放到各种不同的位置,所以你可能需要找找其他的地方,或者通过配置文件查看这些日志文件配置到了什么地方。

   正如其名字所示,访问日志access_log记录了所有对Web服务器的访问活动。下面是访问日志中一个典型的记录:

216.35.116.91 – – [19/Aug/2000:14:47:37 -0400] “GET / HTTP/1.0” 200 654

   这行内容由7项构成,上面的例子中有两项空白,但整行内容仍旧分成了7项。

   第一项信息是远程主机的地址,即它表明访问网站的究竟是谁。在上面的例子中,访问网站的主机是216.35.116.91。随便说一句,这个地址属于一台名为si3001.inktomi.com的机器(要找出这个信息,可以使用nslookup工具查找DNS),inktomi.com是一家制作Web搜索软件的公司。可以看出,仅仅从日志记录的第一项出发,我们就可以得到有关访问者的不少信息。

   默认情况下,第一项信息只是远程主机的IP地址,但我们可以要求Apache查出所有的主机名字,并在日志文件中用主机名字来替代IP地址。然而,这种做法通常不值得推荐,因为它将极大地影响服务器记录日志的速度,从而也就减低了整个网站的效率。另外,有许多工具能够将日志文件中的IP地址转换成主机名字,因此要求Apache记录主机名字替代IP地址是得不偿失的。

   然而,如果确实有必要让Apache找出远程主机的名字,那么我们可以使用如下指令:

HostNameLookups on

   如果HostNameLookups设置成double而不是on,日志记录程序将对它找到的主机名字进行反向查找,验证该主机名字确实指向了原来出现的IP地址。默认情况下HostNameLookups设置为off。

   上例日志记录中的第二项是空白,用一个“-”占位符替代。实际上绝大多数时候这一项都是如此。这个位置用于记录浏览者的标识,这不只是浏览者的登录名字,而是浏览者的email地址或者其他唯一标识符。这个信息由identd返回,或者直接由浏览器返回。很早的时候,那时Netscape 0.9还占据着统治地位,这个位置往往记录着浏览者的email地址。然而,由于有人用它来收集邮件地址和发送垃圾邮件,所以它未能保留多久,很久之前市场上几乎所有的浏览器就取消了这项功能。因此,到了今天,我们在日志记录的第二项看到email地址的机会已经微乎其微了。

   日志记录的第三项也是空白。这个位置用于记录浏览者进行身份验证时提供的名字。当然,如果网站的某些内容要求用户进行身份验证,那么这项信息是不会空白的。但是,对于大多数网站来说,日志文件的大多数记录中这一项仍旧是空白的。

   日志记录的第四项是请求的时间。这个信息用方括号包围,而且采用所谓的“公共日志格式”或“标准英文格式”。因此,上例日志记录表示请求的时间是2000年8月19日星期三14:47:37。时间信息最后的“-0400”表示服务器所处时区位于UTC之前的4小时。

   日志记录的第五项信息或许是整个日志记录中最有用的信息,它告诉我们服务器收到的是一个什么样的请求。该项信息的典型格式是“METHOD RESOURCE PROTOCOL”,即“方法 资源 协议”。

   在上例中,METHOD是GET,其他经常可能出现的METHOD还有POST和HEAD。此外还有不少可能出现的合法METHOD,但主要就是这三种。

   RESOURCE是指浏览者向服务器请求的文档,或URL。在这个例子中,浏览者请求的是“/”,即网站的主页或根。大多数情况下,“/”指向DocumentRoot目录的index.html文档,但根据服务器配置的不同它也可能指向其他文件。

   PROTOCOL通常是HTTP,后面再加上版本号。版本号或者是1.0,或者是1.1,但出现1.0的时候比较多。我们知道,HTTP协议是Web得以工作的基础,HTTP/1.0是HTTP协议的早期版本,而1.1是最近的版本。当前大多数Web客户程序仍使用1.0版本的HTTP协议。

   日志记录的第六项信息是状态代码。它告诉我们请求是否成功,或者遇到了什么样的错误。大多数时候,这项值是200,它表示服务器已经成功地响应浏览器的请求,一切正常。此处不准备给出状态代码的完整清单以及解释它们的含义,请参考相关资料了解这方面的信息。但一般地说,以2开头的状态代码表示成功,以3开头的状态代码表示由于各种不同的原因用户请求被重定向到了其他位置,以4开头的状态代码表示客户端存在某种错误,以5开头的状态代码表示服务器遇到了某个错误。

   日志记录的第七项表示发送给客户端的总字节数。它告诉我们传输是否被打断(即,该数值是否和文件的大小相同)。把日志记录中的这些值加起来就可以得知服务器在一天、一周或者一月内发送了多少数据。

二、配置访问日志

   访问日志文件的位置实际上是一个配置选项。如果我们检查httpd.conf配置文件,可以看到该文件中有如下这行内容:

CustomLog /usr/local/apache/logs/access_log common

   注意,对于版本较早的Apache服务器,这行内容可能略有不同。它使用的可能不是CustomLog指令,而是TransferLog指令。如果你的服务器属于这类情况,建议你尽可能地早日升级服务器。

   CustomLog指令指定了保存日志文件的具体位置以及日志的格式。至于如何定制日志文件的格式以及内容,我们将在这个《Apache日志》系列文章的后面几篇讨论。上面这行指令指定的是common日志格式,自从有了Web服务器开始,common格式就是它的标准格式。由此我们也可以理解,虽然几乎不再有任何客户程序向服务器提供用户的标识信息,但访问日志却还保留着第二项内容。

   CustomLog指令中的路径是日志文件的路径。注意,由于日志文件是由HTTP用户打开的(用User指令指定),因此必须注意这个路径要有安全保证,防止该文件被随意改写。

   《Apache日志》系列文章的后面几篇将继续介绍:Apache错误日志,定制日志的格式和内容,如何将日志内容写入指定的程序而不是文件,如何从日志文件获得一些非常有用的统计信息,等等。

Apche日志系列(2):错误日志

错误日志和访问日志一样也是Apache的标准日志。本文分析错误日志的内容,介绍如何设置和错误日志相关的选项,文档错误和CGI错误的分类,以及如何方便地查看日志内容,等等。

一、位置和内容

   前文讨论了Apache的访问日志,包括它的内容、格式和如何设置访问日志有关的选项。本文我们要讨论的是另外一种Apache标准日志——错误日志。

   错误日志无论在格式上还是在内容上都和访问日志不同。然而,错误日志和访问日志一样也提供丰富的信息,我们可以利用这些信息分析服务器的运行情况、哪里出现了问题。

   错误日志的文件名字是error_log,但如果是Windows平台,则错误日志的文件名字是error.log。错误日志的位置可以通过ErrorLog指令设置:

ErrorLog logs/error.log

   除非文件位置用“/”开头,否则这个文件位置是相对于ServerRoot目录的相对路径。如果Apache采用默认安装方式安装,那么错误日志的位置应该在/usr/local/apache/logs下。但是,如果Apache用某种包管理器安装,错误日志很可能在其他位置。

   正如其名字所示,错误日志记录了服务器运行期间遇到的各种错误,以及一些普通的诊断信息,比如服务器何时启动、何时关闭等。

   我们可以设置日志文件记录信息级别的高低,控制日志文件记录信息的数量和类型。这是通过LogLevel指令设置的,该指令默认设置的级别是error,即记录称得上错误的事件。有关该指令中允许设置的各种选项的完整清单,请参见http://www.apache.org/docs/mod/core.html#loglevel的Apache文档。

   大多数情况下,我们在日志文件中见到的内容分属两类:文档错误和CGI错误。但是,错误日志中偶尔也会出现配置错误,另外还有前面提到的服务器启动和关闭信息。

二、文档错误

   文档错误和服务器应答中的400系列代码相对应,最常见的就是404错误——Document Not Found(文档没有找到)。除了404错误以外,用户身份验证错误也是一种常见的错误。

   404错误在用户请求的资源(即URL)不存在时出现,它可能是由于用户输入的URL错误,或者由于服务器上原来存在的文档因故被删除或移动。

   顺便说一下,按照Jakob Nielson的意见,在不提供重定向或者其他补救措施的情况下,我们永远不应该移动或者删除Web网站的任何资源。Nielson的更多文章,请参见http://www.zdnet.com/devhead/alertbox/。

   当用户不能打开服务器上的文档时,错误日志中出现的记录如下所示:

[Fri Aug 18 22:36:26 2000] [error]

[client 192.168.1.6] File does not exist:

/usr/local/apache/bugletdocs/Img/south-korea.gif
   可以看到,正如访问日志access_log文件一样,错误日志记录也分成多个项。

   错误记录的开头是日期/时间标记,注意它们的格式和access_log中日期/时间的格式不同。access_log中的格式被称为“标准英文格式”,这或许是历史跟我们开的一个玩笑,但现在要改变它已经太迟了。

   错误记录的第二项是当前记录的级别,它表明了问题的严重程度。这个级别信息可能是LogLevel指令的文档中所列出的任一级别(参见前面LogLevel的链接),error级别处于warn级别和crit级别之间。404属于error错误级别,这个级别表示确实遇到了问题,但服务器还可以运行。

   错误记录的第三项表示用户发出请求时所用的IP地址。

   记录的最后一项才是真正的错误信息。对于404错误,它还给出了完整路径指示服务器试图访问的文件。当我们料想某个文件应该在目标位置却出现了404错误时,这个信息是非常有用的。此时产生这种错误的原因往往是由于服务器配置错误、文件实际所处的虚拟主机和我们料想的不同,或者其他一些意料不到的情况。

   由于用户身份验证问题而出现的错误记录如下所示:

[Tue Apr 11 22:13:21 2000]

[error] [client 192.168.1.3] user rbowen@rcbowen.

com: authentication failure for “/cgi-bin/hirecareers/company.cgi”:

password mismatch

   注意,由于文档错误是用户请求的直接结果,因此它们在访问日志中也会有相应的记录。

三、CGI错误
   错误日志最主要的用途或许是诊断行为异常的CGI程序。为了进一步分析和处理方便,CGI程序输出到STDERR(Standard Error,标准错误设备)的所有内容都将直接进入错误日志。这意味着,任何编写良好的CGI程序,如果出现了问题,错误日志就会告诉我们有关问题的详细信息。

   然而,把CGI程序错误输出到错误日志也有它的缺点,错误日志中将出现许多没有标准格式的内容,这使得用错误日志自动分析程序从中分析出有用的信息变得相当困难。

   下面是一个例子,它是调试Perl CGI代码时,错误日志中出现的一个错误记录:

[Wed Jun 14 16:16:37 2000] [error] [client 192.168.1.3] Premature

end of script headers: /usr/local/apache/cgi-bin/HyperCalPro/announcement.cgi

Global symbol “$rv” requires explicit package name at

/usr/local/apache/cgi-bin/HyperCalPro/announcement.cgi line 81.

Global symbol “�tails” requires explicit package name at

/usr/local/apache/cgi-bin/HyperCalPro/announcement.cgi line 84.

Global symbol “$Config” requires explicit package name at

/usr/local/apache/cgi-bin/HyperCalPro/announcement.cgi line 133.

Execution of /usr/local/apache/cgi-bin/HyperCalPro/announcement.cgi

aborted due to compilation errors.

   可以看到,CGI错误和前面的404错误格式相同,包含日期/时间、错误级别以及客户地址、错误信息。但这个CGI错误的错误信息有好几行,这往往会干扰一些错误日志分析软件的工作。

   有了这个错误信息,即使是对Perl不太熟悉的人也能够找出许多有关错误的信息,例如至少可以方便地得知是哪几行代码出现了问题。Perl在报告程序错误方面的机制是相当完善的。当然,不同的编程语言输出到错误日志的信息会有所不同。

   由于CGI程序运行环境的特殊性,如果没有错误日志的帮助,大多数CGI程序的错误都将很难解决。

   有不少人在邮件列表或者新闻组中抱怨说自己有一个CGI程序,当打开网页时服务器却返回错误,比如“Internal Server Error”。我们可以肯定,这些人还没有看过服务器的错误日志,或者根本不知道错误日志的存在。决多大多数情况下,错误日志能够精确地指出CGI错误的所在以及如何修正这个错误。

四、查看日志文件

   我常常告诉别人说,在进行开发的同时我会不断地检查服务器的日志,以便能够立即知道哪儿出了问题。但我得到的回答却往往是沉默。起先我以为这种沉默意味着“你当然得这样做”,后来我才发现这种沉默的真正含义是“我不知道别人的做法,但我自己是不干的。”

   虽然如此,下面我们还是要看看如何方便地查看服务器日志文件。用telnet连接到服务器,然后输入下面的命令:

tail -f /usr/local/apache/logs/error_log

   该命令将显示出日志文件的最后几行内容,如果有新的内容加入到日志文件,它还会立即显示出新加入的内容。

   Windows用户也同样可以使用这种方法,比如可以使用各种为Windows提供的Unix工具软件包。我个人爱好一个称为AINTX的工具,它可以在http://maxx.mc.net/~jlh/nttools/index.htm找到。

   还有一种替代方法是使用下面的Perl代码,它利用了一个称为File::Tail的模块:

use File::Tail;

$file=File::Tail->;new(“/some/log/file”);

while (defined($line=$file->;read)) {

print “$line”;

}

   无论具体采用的是哪一种方法,同时打开多个终端窗口都是一种好习惯:比如在一个窗口中显示错误日志,在另一个窗口中显示访问日志。这样,我们就能够随时获知网站上发生的事情并立即予以解决。

   在这个《Apache日志》系列的下一篇文章中,我们将讨论定制服务器日志,即如何在日志文件中记录所有我们想要的信息,排除所有我们不想要的信息。

   在此之后,我们还将讨论日志文件的处理,即如何从日志文件生成统计报表。在最后几篇文章中,我们还将讨论如何把日志记录重定向到指定的程序而不是保存到日志文件,以便由程序实时地处理新生成的日志数据,比如将日志数据保存到数据库,或者当发生某些关键性错误时通过email把日志信息发送给系统管理员,等等。

Apche日志系列(3):定制日志

有时候我们需要定制Apache默认日志的格式和内容,比如增加或减少日志所记录的信息、改变默认日志文件的格式等。本文介绍可以用日志记录的所有信息,以及如何设置Apache使其记录这些信息。

一、定义日志格式(4月3日)

   很久以前,日志文件只有一种格式,这就是“公共格式”,许多人已经习惯于使用这种格式。随后出现了定制日志格式,而且看起来定制日志格式更很受欢迎,即使公共日志格式本身也重新用定制日志格式定义。本文介绍的就是如何随心所欲地定制日志文件的格式、如何让日志文件记录自己想要的信息。

   定制日志文件的格式涉及到两个指令,即LogFormat指令和CustomLog指令,默认httpd.conf文件提供了关于这两个指令的几个示例。

   LogFormat指令定义格式并为格式指定一个名字,以后我们就可以直接引用这个名字。CustomLog指令设置日志文件,并指明日志文件所用的格式(通常通过格式的名字)。

   LogFormat指令的功能是定义日志格式并为它指定一个名字。例如,在默认的httpd.conf文件中,我们可以找到下面这行代码:

LogFormat “%h %l %u %t \”%r\” %>;s %b” common

   该指令创建了一种名为“common”的日志格式,日志的格式在双引号包围的内容中指定。格式字符串中的每一个变量代表着一项特定的信息,这些信息按照格式串规定的次序写入到日志文件。

   Apache文档已经给出了所有可用于格式串的变量及其含义,下面是其译文:

———————————————————————-

%…a: 远程IP地址

%…A: 本地IP地址

%…B: 已发送的字节数,不包含HTTP头

%…b: CLF格式的已发送字节数量,不包含HTTP头。

例如当没有发送数据时,写入‘-’而不是0。

%e: 环境变量FOOBAR的内容

%…f: 文件名字

%…h: 远程主机

%…H 请求的协议

%i: Foobar的内容,发送给服务器的请求的标头行。

%…l: 远程登录名字(来自identd,如提供的话)

%…m 请求的方法

%n: 来自另外一个模块的注解“Foobar”的内容

%o: Foobar的内容,应答的标头行

%…p: 服务器响应请求时使用的端口

%…P: 响应请求的子进程ID。

%…q 查询字符串(如果存在查询字符串,则包含“?”后面的

部分;否则,它是一个空字符串。)

%…r: 请求的第一行

%…s: 状态。对于进行内部重定向的请求,这是指*原来*请求

的状态。如果用%…>;s,则是指后来的请求。

%…t: 以公共日志时间格式表示的时间(或称为标准英文格式)

%t: 以指定格式format表示的时间

%…T: 为响应请求而耗费的时间,以秒计

%…u: 远程用户(来自auth;如果返回状态(%s)是401则可能是伪造的)

%…U: 用户所请求的URL路径

%…v: 响应请求的服务器的ServerName

%…V: 依照UseCanonicalName设置得到的服务器名字

——————————————————————

   在所有上面列出的变量中,“…”表示一个可选的条件。如果没有指定条件,则变量的值将以“-”取代。分析前面来自默认httpd.conf文件的LogFormat指令示例,可以看出它创建了一种名为“common”的日志格式,其中包括:远程主机,远程登录名字,远程用户,请求时间,请求的第一行代码,请求状态,以及发送的字节数。

   有时候我们只想在日志中记录某些特定的、已定义的信息,这时就要用到“…”。如果在“%”和变量之间放入了一个或者多个HTTP状态代码,则只有当请求返回的状态代码属于指定的状态代码之一时,变量所代表的内容才会被记录。例如,如果我们想要记录的是网站的所有无效链接,那么可以使用:

—————————————————-

LogFormat @4{Referer}i BrokenLinks

—————————————————

   反之,如果我们想要记录那些状态代码不等于指定值的请求,只需加入一个“!”符号即可:

LogFormat %!200U SomethingWrong

Apche日志系列(4):日志分析

尽管日志文件中包含着大量有用的信息,但这些信息只有在经过深入挖掘之后才能够最大限度地发挥作用。本文首先讨论了能够从日志文件获得的信息以及不能从日志文件获得的信息,然后介绍了几种优秀的日志分析工具以及如何自己编程分析日志文件。

一、可以得到哪些信息(4月4日)

   在这个《Apache日志》系列文章的前面几篇中,我们讨论了Apache的标准日志文件——访问日志和错误日志,以及如何定制日志文件。本文接下来讨论如何分析日志文件获得宝贵的统计信息。

   我们面临的问题是,虽然日志文件中包含了大量的信息,但这些信息对于我们管理、规划网站却没有多少直接的帮助。为了管理和规划网站,我们需要知道:有多少人浏览了网站,他们在看些什么,停留了多长时间,他们从哪里得知这个网站,等等。所有这些信息就隐藏于(或者可能隐藏于)日志文件之中。

   就网站的经营者而言,他们还希望知道浏览者的姓名、地址、鞋子大小,甚至还有浏览者的信用卡号码,但这些信息都不可能从日志文件中得到。为此,作为技术人员的我们就必须知道如何向这些经营者解释清楚:这部分信息不仅不可能从日志文件获得,而且要获得这些信息的唯一方法是直接向浏览者本人询问,并作好被拒绝的准备。

   有许多信息可以用日志文件来记录,其中包括:

远程机器的地址:“远程机器的地址”和“谁在浏览网站”差不多,但并不等同。具体地说,远程机器的地址告诉我们浏览者来自何方,比如它可能是buglet.rcbowen.com或者proxy01.aol.com。

浏览时间:浏览者何时开始访问网站?从这个问题的答案中我们能够了解不少情况。如果网站的大多数浏览者都在早上9:00和下午4:00之间访问网站,那么可以相信网站的浏览者大多数总在工作时间进行访问;如果访问记录大多出现在下午7:00到午夜之间,我们可以肯定浏览者一般在家里上网。 当然,从单个访问记录能够得到的信息非常有限,但如果从数千个访问记录出发,我们就可以得到非常有用和重要的统计信息。

用户所访问的资源:网站的哪些部分最受用户欢迎?这些最受欢迎的部分就是我们应该继续加以发展的部分。网站的哪些部分总是受到冷落?网站中这些受到冷落的部分或许隐藏得太深,或许它们确实没有什么意思,此时我们就得想办法加以改进。当然,网站还有的内容,比如法律上的声明,虽然很少有人访问,但却不应该随便地改动它们。

无效链接:当然,日志文件还能够告诉我们哪些东西不能按照我们所想象地运行。网站中是否存在错误的链接?其他网站链接过来时有没有搞错URL?是否存在不能正常运行的CGI程序?是否有搜索引擎检索程序每秒发出数千个请求,从而影响了本网站的正常服务?这些问题的答案都可以从日志文件找到线索
1,查看apache进程:
ps aux | grep httpd | grep -v grep | wc -l
2,查看80端口的tcp连接:
netstat -tan | grep “ESTABLISHED” | grep “:80” | wc -l
3,通过日志查看当天ip连接数,过滤重复:
cat access_log | grep “20/Oct/2008” | awk ‘{print $1}’ | sort | uniq -c | sort -rn
4,当天ip连接数最高的ip都在干些什么(原来是蜘蛛):
cat access_log | grep “20/Oct/2008:00” | grep “122.102.7.212” | awk ‘{print $7}’ | sort | uniq -c | sort -rn | head -n 10
5,当天访问页面排前10的url:
cat access_log | awk ‘{if($8 ~ /HTTP\/1.1/)print $7}’ | sort | uniq -c | sort -nr | head -n 10
6,用tcpdump嗅探80端口的访问看看谁最高
tcpdump -i eth0 -t dst port 80 -c 1000 | awk -F”.” ‘{print $1″.”$2″.”$3″.”$4}’ | sort | uniq -c | sort –rn
7,查看某一时间段的ip连接数:
grep “2006:0[7-8]” access_log | awk ‘{print $2}’ | sort | uniq -c| sort -nr | wc -l想要知道什么人在什么时候浏览了网站的哪些内容吗?查看Apache的访问日志就可以知道。访问日志是Apache的标准日志,本文详细解释了访问日志的内容以及相关选项的配置。

一、访问日志的格式

   Apache内建了记录服务器活动的功能,这就是它的日志功能。这个《Apache日志》系列文章介绍的就是Apache的访问日志、错误日志,以及如何分析日志数据,如何定制Apache日志,如何从日志数据生成统计报表等内容。

   如果Apache的安装方式是默认安装,服务器一运行就会有两个日志文件生成。这两个文件是access_log(在Windows上是access.log)和error_log(在Windows上是error.log)。采用默认安装方式时,这些文件可以在/usr/local/apache/logs下找到;对于Windows系统,这些日志文件将保存在Apache安装目录的logs子目录。不同的包管理器会把日志文件放到各种不同的位置,所以你可能需要找找其他的地方,或者通过配置文件查看这些日志文件配置到了什么地方。

   正如其名字所示,访问日志access_log记录了所有对Web服务器的访问活动。下面是访问日志中一个典型的记录:

216.35.116.91 – – [19/Aug/2000:14:47:37 -0400] “GET / HTTP/1.0” 200 654

   这行内容由7项构成,上面的例子中有两项空白,但整行内容仍旧分成了7项。

   第一项信息是远程主机的地址,即它表明访问网站的究竟是谁。在上面的例子中,访问网站的主机是216.35.116.91。随便说一句,这个地址属于一台名为si3001.inktomi.com的机器(要找出这个信息,可以使用nslookup工具查找DNS),inktomi.com是一家制作Web搜索软件的公司。可以看出,仅仅从日志记录的第一项出发,我们就可以得到有关访问者的不少信息。

   默认情况下,第一项信息只是远程主机的IP地址,但我们可以要求Apache查出所有的主机名字,并在日志文件中用主机名字来替代IP地址。然而,这种做法通常不值得推荐,因为它将极大地影响服务器记录日志的速度,从而也就减低了整个网站的效率。另外,有许多工具能够将日志文件中的IP地址转换成主机名字,因此要求Apache记录主机名字替代IP地址是得不偿失的。

   然而,如果确实有必要让Apache找出远程主机的名字,那么我们可以使用如下指令:

HostNameLookups on

   如果HostNameLookups设置成double而不是on,日志记录程序将对它找到的主机名字进行反向查找,验证该主机名字确实指向了原来出现的IP地址。默认情况下HostNameLookups设置为off。

   上例日志记录中的第二项是空白,用一个“-”占位符替代。实际上绝大多数时候这一项都是如此。这个位置用于记录浏览者的标识,这不只是浏览者的登录名字,而是浏览者的email地址或者其他唯一标识符。这个信息由identd返回,或者直接由浏览器返回。很早的时候,那时Netscape 0.9还占据着统治地位,这个位置往往记录着浏览者的email地址。然而,由于有人用它来收集邮件地址和发送垃圾邮件,所以它未能保留多久,很久之前市场上几乎所有的浏览器就取消了这项功能。因此,到了今天,我们在日志记录的第二项看到email地址的机会已经微乎其微了。

   日志记录的第三项也是空白。这个位置用于记录浏览者进行身份验证时提供的名字。当然,如果网站的某些内容要求用户进行身份验证,那么这项信息是不会空白的。但是,对于大多数网站来说,日志文件的大多数记录中这一项仍旧是空白的。

   日志记录的第四项是请求的时间。这个信息用方括号包围,而且采用所谓的“公共日志格式”或“标准英文格式”。因此,上例日志记录表示请求的时间是2000年8月19日星期三14:47:37。时间信息最后的“-0400”表示服务器所处时区位于UTC之前的4小时。

   日志记录的第五项信息或许是整个日志记录中最有用的信息,它告诉我们服务器收到的是一个什么样的请求。该项信息的典型格式是“METHOD RESOURCE PROTOCOL”,即“方法 资源 协议”。

   在上例中,METHOD是GET,其他经常可能出现的METHOD还有POST和HEAD。此外还有不少可能出现的合法METHOD,但主要就是这三种。

   RESOURCE是指浏览者向服务器请求的文档,或URL。在这个例子中,浏览者请求的是“/”,即网站的主页或根。大多数情况下,“/”指向DocumentRoot目录的index.html文档,但根据服务器配置的不同它也可能指向其他文件。

   PROTOCOL通常是HTTP,后面再加上版本号。版本号或者是1.0,或者是1.1,但出现1.0的时候比较多。我们知道,HTTP协议是Web得以工作的基础,HTTP/1.0是HTTP协议的早期版本,而1.1是最近的版本。当前大多数Web客户程序仍使用1.0版本的HTTP协议。

   日志记录的第六项信息是状态代码。它告诉我们请求是否成功,或者遇到了什么样的错误。大多数时候,这项值是200,它表示服务器已经成功地响应浏览器的请求,一切正常。此处不准备给出状态代码的完整清单以及解释它们的含义,请参考相关资料了解这方面的信息。但一般地说,以2开头的状态代码表示成功,以3开头的状态代码表示由于各种不同的原因用户请求被重定向到了其他位置,以4开头的状态代码表示客户端存在某种错误,以5开头的状态代码表示服务器遇到了某个错误。

   日志记录的第七项表示发送给客户端的总字节数。它告诉我们传输是否被打断(即,该数值是否和文件的大小相同)。把日志记录中的这些值加起来就可以得知服务器在一天、一周或者一月内发送了多少数据。

二、配置访问日志

   访问日志文件的位置实际上是一个配置选项。如果我们检查httpd.conf配置文件,可以看到该文件中有如下这行内容:

CustomLog /usr/local/apache/logs/access_log common

   注意,对于版本较早的Apache服务器,这行内容可能略有不同。它使用的可能不是CustomLog指令,而是TransferLog指令。如果你的服务器属于这类情况,建议你尽可能地早日升级服务器。

   CustomLog指令指定了保存日志文件的具体位置以及日志的格式。至于如何定制日志文件的格式以及内容,我们将在这个《Apache日志》系列文章的后面几篇讨论。上面这行指令指定的是common日志格式,自从有了Web服务器开始,common格式就是它的标准格式。由此我们也可以理解,虽然几乎不再有任何客户程序向服务器提供用户的标识信息,但访问日志却还保留着第二项内容。

   CustomLog指令中的路径是日志文件的路径。注意,由于日志文件是由HTTP用户打开的(用User指令指定),因此必须注意这个路径要有安全保证,防止该文件被随意改写。

   《Apache日志》系列文章的后面几篇将继续介绍:Apache错误日志,定制日志的格式和内容,如何将日志内容写入指定的程序而不是文件,如何从日志文件获得一些非常有用的统计信息,等等。

Apche日志系列(2):错误日志

错误日志和访问日志一样也是Apache的标准日志。本文分析错误日志的内容,介绍如何设置和错误日志相关的选项,文档错误和CGI错误的分类,以及如何方便地查看日志内容,等等。

一、位置和内容

   前文讨论了Apache的访问日志,包括它的内容、格式和如何设置访问日志有关的选项。本文我们要讨论的是另外一种Apache标准日志——错误日志。

   错误日志无论在格式上还是在内容上都和访问日志不同。然而,错误日志和访问日志一样也提供丰富的信息,我们可以利用这些信息分析服务器的运行情况、哪里出现了问题。

   错误日志的文件名字是error_log,但如果是Windows平台,则错误日志的文件名字是error.log。错误日志的位置可以通过ErrorLog指令设置:

ErrorLog logs/error.log

   除非文件位置用“/”开头,否则这个文件位置是相对于ServerRoot目录的相对路径。如果Apache采用默认安装方式安装,那么错误日志的位置应该在/usr/local/apache/logs下。但是,如果Apache用某种包管理器安装,错误日志很可能在其他位置。

   正如其名字所示,错误日志记录了服务器运行期间遇到的各种错误,以及一些普通的诊断信息,比如服务器何时启动、何时关闭等。

   我们可以设置日志文件记录信息级别的高低,控制日志文件记录信息的数量和类型。这是通过LogLevel指令设置的,该指令默认设置的级别是error,即记录称得上错误的事件。有关该指令中允许设置的各种选项的完整清单,请参见http://www.apache.org/docs/mod/core.html#loglevel的Apache文档。

   大多数情况下,我们在日志文件中见到的内容分属两类:文档错误和CGI错误。但是,错误日志中偶尔也会出现配置错误,另外还有前面提到的服务器启动和关闭信息。

二、文档错误

   文档错误和服务器应答中的400系列代码相对应,最常见的就是404错误——Document Not Found(文档没有找到)。除了404错误以外,用户身份验证错误也是一种常见的错误。

   404错误在用户请求的资源(即URL)不存在时出现,它可能是由于用户输入的URL错误,或者由于服务器上原来存在的文档因故被删除或移动。

   顺便说一下,按照Jakob Nielson的意见,在不提供重定向或者其他补救措施的情况下,我们永远不应该移动或者删除Web网站的任何资源。Nielson的更多文章,请参见http://www.zdnet.com/devhead/alertbox/。

   当用户不能打开服务器上的文档时,错误日志中出现的记录如下所示:

[Fri Aug 18 22:36:26 2000] [error]

[client 192.168.1.6] File does not exist:

/usr/local/apache/bugletdocs/Img/south-korea.gif
   可以看到,正如访问日志access_log文件一样,错误日志记录也分成多个项。

   错误记录的开头是日期/时间标记,注意它们的格式和access_log中日期/时间的格式不同。access_log中的格式被称为“标准英文格式”,这或许是历史跟我们开的一个玩笑,但现在要改变它已经太迟了。

   错误记录的第二项是当前记录的级别,它表明了问题的严重程度。这个级别信息可能是LogLevel指令的文档中所列出的任一级别(参见前面LogLevel的链接),error级别处于warn级别和crit级别之间。404属于error错误级别,这个级别表示确实遇到了问题,但服务器还可以运行。

   错误记录的第三项表示用户发出请求时所用的IP地址。

   记录的最后一项才是真正的错误信息。对于404错误,它还给出了完整路径指示服务器试图访问的文件。当我们料想某个文件应该在目标位置却出现了404错误时,这个信息是非常有用的。此时产生这种错误的原因往往是由于服务器配置错误、文件实际所处的虚拟主机和我们料想的不同,或者其他一些意料不到的情况。

   由于用户身份验证问题而出现的错误记录如下所示:

[Tue Apr 11 22:13:21 2000]

[error] [client 192.168.1.3] user rbowen@rcbowen.

com: authentication failure for “/cgi-bin/hirecareers/company.cgi”:

password mismatch

   注意,由于文档错误是用户请求的直接结果,因此它们在访问日志中也会有相应的记录。

三、CGI错误
   错误日志最主要的用途或许是诊断行为异常的CGI程序。为了进一步分析和处理方便,CGI程序输出到STDERR(Standard Error,标准错误设备)的所有内容都将直接进入错误日志。这意味着,任何编写良好的CGI程序,如果出现了问题,错误日志就会告诉我们有关问题的详细信息。

   然而,把CGI程序错误输出到错误日志也有它的缺点,错误日志中将出现许多没有标准格式的内容,这使得用错误日志自动分析程序从中分析出有用的信息变得相当困难。

   下面是一个例子,它是调试Perl CGI代码时,错误日志中出现的一个错误记录:

[Wed Jun 14 16:16:37 2000] [error] [client 192.168.1.3] Premature

end of script headers: /usr/local/apache/cgi-bin/HyperCalPro/announcement.cgi

Global symbol “$rv” requires explicit package name at

/usr/local/apache/cgi-bin/HyperCalPro/announcement.cgi line 81.

Global symbol “�tails” requires explicit package name at

/usr/local/apache/cgi-bin/HyperCalPro/announcement.cgi line 84.

Global symbol “$Config” requires explicit package name at

/usr/local/apache/cgi-bin/HyperCalPro/announcement.cgi line 133.

Execution of /usr/local/apache/cgi-bin/HyperCalPro/announcement.cgi

aborted due to compilation errors.

   可以看到,CGI错误和前面的404错误格式相同,包含日期/时间、错误级别以及客户地址、错误信息。但这个CGI错误的错误信息有好几行,这往往会干扰一些错误日志分析软件的工作。

   有了这个错误信息,即使是对Perl不太熟悉的人也能够找出许多有关错误的信息,例如至少可以方便地得知是哪几行代码出现了问题。Perl在报告程序错误方面的机制是相当完善的。当然,不同的编程语言输出到错误日志的信息会有所不同。

   由于CGI程序运行环境的特殊性,如果没有错误日志的帮助,大多数CGI程序的错误都将很难解决。

   有不少人在邮件列表或者新闻组中抱怨说自己有一个CGI程序,当打开网页时服务器却返回错误,比如“Internal Server Error”。我们可以肯定,这些人还没有看过服务器的错误日志,或者根本不知道错误日志的存在。决多大多数情况下,错误日志能够精确地指出CGI错误的所在以及如何修正这个错误。

四、查看日志文件

   我常常告诉别人说,在进行开发的同时我会不断地检查服务器的日志,以便能够立即知道哪儿出了问题。但我得到的回答却往往是沉默。起先我以为这种沉默意味着“你当然得这样做”,后来我才发现这种沉默的真正含义是“我不知道别人的做法,但我自己是不干的。”

   虽然如此,下面我们还是要看看如何方便地查看服务器日志文件。用telnet连接到服务器,然后输入下面的命令:

tail -f /usr/local/apache/logs/error_log

   该命令将显示出日志文件的最后几行内容,如果有新的内容加入到日志文件,它还会立即显示出新加入的内容。

   Windows用户也同样可以使用这种方法,比如可以使用各种为Windows提供的Unix工具软件包。我个人爱好一个称为AINTX的工具,它可以在http://maxx.mc.net/~jlh/nttools/index.htm找到。

   还有一种替代方法是使用下面的Perl代码,它利用了一个称为File::Tail的模块:

use File::Tail;

$file=File::Tail->;new(“/some/log/file”);

while (defined($line=$file->;read)) {

print “$line”;

}

   无论具体采用的是哪一种方法,同时打开多个终端窗口都是一种好习惯:比如在一个窗口中显示错误日志,在另一个窗口中显示访问日志。这样,我们就能够随时获知网站上发生的事情并立即予以解决。

   在这个《Apache日志》系列的下一篇文章中,我们将讨论定制服务器日志,即如何在日志文件中记录所有我们想要的信息,排除所有我们不想要的信息。

   在此之后,我们还将讨论日志文件的处理,即如何从日志文件生成统计报表。在最后几篇文章中,我们还将讨论如何把日志记录重定向到指定的程序而不是保存到日志文件,以便由程序实时地处理新生成的日志数据,比如将日志数据保存到数据库,或者当发生某些关键性错误时通过email把日志信息发送给系统管理员,等等。

Apche日志系列(3):定制日志

有时候我们需要定制Apache默认日志的格式和内容,比如增加或减少日志所记录的信息、改变默认日志文件的格式等。本文介绍可以用日志记录的所有信息,以及如何设置Apache使其记录这些信息。

一、定义日志格式(4月3日)

   很久以前,日志文件只有一种格式,这就是“公共格式”,许多人已经习惯于使用这种格式。随后出现了定制日志格式,而且看起来定制日志格式更很受欢迎,即使公共日志格式本身也重新用定制日志格式定义。本文介绍的就是如何随心所欲地定制日志文件的格式、如何让日志文件记录自己想要的信息。

   定制日志文件的格式涉及到两个指令,即LogFormat指令和CustomLog指令,默认httpd.conf文件提供了关于这两个指令的几个示例。

   LogFormat指令定义格式并为格式指定一个名字,以后我们就可以直接引用这个名字。CustomLog指令设置日志文件,并指明日志文件所用的格式(通常通过格式的名字)。

   LogFormat指令的功能是定义日志格式并为它指定一个名字。例如,在默认的httpd.conf文件中,我们可以找到下面这行代码:

LogFormat “%h %l %u %t \”%r\” %>;s %b” common

   该指令创建了一种名为“common”的日志格式,日志的格式在双引号包围的内容中指定。格式字符串中的每一个变量代表着一项特定的信息,这些信息按照格式串规定的次序写入到日志文件。

   Apache文档已经给出了所有可用于格式串的变量及其含义,下面是其译文:

———————————————————————-

%…a: 远程IP地址

%…A: 本地IP地址

%…B: 已发送的字节数,不包含HTTP头

%…b: CLF格式的已发送字节数量,不包含HTTP头。

例如当没有发送数据时,写入‘-’而不是0。

%e: 环境变量FOOBAR的内容

%…f: 文件名字

%…h: 远程主机

%…H 请求的协议

%i: Foobar的内容,发送给服务器的请求的标头行。

%…l: 远程登录名字(来自identd,如提供的话)

%…m 请求的方法

%n: 来自另外一个模块的注解“Foobar”的内容

%o: Foobar的内容,应答的标头行

%…p: 服务器响应请求时使用的端口

%…P: 响应请求的子进程ID。

%…q 查询字符串(如果存在查询字符串,则包含“?”后面的

部分;否则,它是一个空字符串。)

%…r: 请求的第一行

%…s: 状态。对于进行内部重定向的请求,这是指*原来*请求

的状态。如果用%…>;s,则是指后来的请求。

%…t: 以公共日志时间格式表示的时间(或称为标准英文格式)

%t: 以指定格式format表示的时间

%…T: 为响应请求而耗费的时间,以秒计

%…u: 远程用户(来自auth;如果返回状态(%s)是401则可能是伪造的)

%…U: 用户所请求的URL路径

%…v: 响应请求的服务器的ServerName

%…V: 依照UseCanonicalName设置得到的服务器名字

——————————————————————

   在所有上面列出的变量中,“…”表示一个可选的条件。如果没有指定条件,则变量的值将以“-”取代。分析前面来自默认httpd.conf文件的LogFormat指令示例,可以看出它创建了一种名为“common”的日志格式,其中包括:远程主机,远程登录名字,远程用户,请求时间,请求的第一行代码,请求状态,以及发送的字节数。

   有时候我们只想在日志中记录某些特定的、已定义的信息,这时就要用到“…”。如果在“%”和变量之间放入了一个或者多个HTTP状态代码,则只有当请求返回的状态代码属于指定的状态代码之一时,变量所代表的内容才会被记录。例如,如果我们想要记录的是网站的所有无效链接,那么可以使用:

—————————————————-

LogFormat @4{Referer}i BrokenLinks

—————————————————

   反之,如果我们想要记录那些状态代码不等于指定值的请求,只需加入一个“!”符号即可:

LogFormat %!200U SomethingWrong

Apche日志系列(4):日志分析

尽管日志文件中包含着大量有用的信息,但这些信息只有在经过深入挖掘之后才能够最大限度地发挥作用。本文首先讨论了能够从日志文件获得的信息以及不能从日志文件获得的信息,然后介绍了几种优秀的日志分析工具以及如何自己编程分析日志文件。

一、可以得到哪些信息(4月4日)

   在这个《Apache日志》系列文章的前面几篇中,我们讨论了Apache的标准日志文件——访问日志和错误日志,以及如何定制日志文件。本文接下来讨论如何分析日志文件获得宝贵的统计信息。

   我们面临的问题是,虽然日志文件中包含了大量的信息,但这些信息对于我们管理、规划网站却没有多少直接的帮助。为了管理和规划网站,我们需要知道:有多少人浏览了网站,他们在看些什么,停留了多长时间,他们从哪里得知这个网站,等等。所有这些信息就隐藏于(或者可能隐藏于)日志文件之中。

   就网站的经营者而言,他们还希望知道浏览者的姓名、地址、鞋子大小,甚至还有浏览者的信用卡号码,但这些信息都不可能从日志文件中得到。为此,作为技术人员的我们就必须知道如何向这些经营者解释清楚:这部分信息不仅不可能从日志文件获得,而且要获得这些信息的唯一方法是直接向浏览者本人询问,并作好被拒绝的准备。

   有许多信息可以用日志文件来记录,其中包括:

远程机器的地址:“远程机器的地址”和“谁在浏览网站”差不多,但并不等同。具体地说,远程机器的地址告诉我们浏览者来自何方,比如它可能是buglet.rcbowen.com或者proxy01.aol.com。

浏览时间:浏览者何时开始访问网站?从这个问题的答案中我们能够了解不少情况。如果网站的大多数浏览者都在早上9:00和下午4:00之间访问网站,那么可以相信网站的浏览者大多数总在工作时间进行访问;如果访问记录大多出现在下午7:00到午夜之间,我们可以肯定浏览者一般在家里上网。 当然,从单个访问记录能够得到的信息非常有限,但如果从数千个访问记录出发,我们就可以得到非常有用和重要的统计信息。

用户所访问的资源:网站的哪些部分最受用户欢迎?这些最受欢迎的部分就是我们应该继续加以发展的部分。网站的哪些部分总是受到冷落?网站中这些受到冷落的部分或许隐藏得太深,或许它们确实没有什么意思,此时我们就得想办法加以改进。当然,网站还有的内容,比如法律上的声明,虽然很少有人访问,但却不应该随便地改动它们。

无效链接:当然,日志文件还能够告诉我们哪些东西不能按照我们所想象地运行。网站中是否存在错误的链接?其他网站链接过来时有没有搞错URL?是否存在不能正常运行的CGI程序?是否有搜索引擎检索程序每秒发出数千个请求,从而影响了本网站的正常服务?这些问题的答案都可以从日志文件找到线索
1,查看apache进程:
ps aux | grep httpd | grep -v grep | wc -l
2,查看80端口的tcp连接:
netstat -tan | grep “ESTABLISHED” | grep “:80” | wc -l
3,通过日志查看当天ip连接数,过滤重复:
cat access_log | grep “20/Oct/2008” | awk ‘{print $1}’ | sort | uniq -c | sort -rn
4,当天ip连接数最高的ip都在干些什么(原来是蜘蛛):
cat access_log | grep “20/Oct/2008:00” | grep “122.102.7.212” | awk ‘{print $7}’ | sort | uniq -c | sort -rn | head -n 10
5,当天访问页面排前10的url:
cat access_log | awk ‘{if($8 ~ /HTTP\/1.1/)print $7}’ | sort | uniq -c | sort -nr | head -n 10
6,用tcpdump嗅探80端口的访问看看谁最高
tcpdump -i eth0 -t dst port 80 -c 1000 | awk -F”.” ‘{print $1″.”$2″.”$3″.”$4}’ | sort | uniq -c | sort –rn
7,查看某一时间段的ip连接数:
grep “2006:0[7-8]” access_log | awk ‘{print $2}’ | sort | uniq -c| sort -nr | wc -l

apache日志分析

1.什么是UV?
UV是unique visitor的简写,是指独立访客,是以实际访问的电脑计数。
2.什么是IP?
IP是国际互联网协议(Internet Protocol)的简称,是通过网络间信息地址定位具体计算机的方式之一。
3.UV和IP的概念有什么区别?
对于IP来说,它在同一级别的网络(例如某个局域网、社区网、教学楼网或者INTERNET)范围内是唯一的,同一局域网内的所有电脑都只有一个共同ip。
举例来说,我在一个局域网里,对外的IP是219.129.170.111,那么跟我同一局域网里的所有电脑都是这个IP,也就是说假如整个局域网的电脑都访问您的网站的话,在24小时内也只计算一个IP,所以相对UV来说不是很精确。
而UV跟IP稍有不同,UV是访问你的网站的每一台电脑客户端。现在很多朋友用的网络都是局域网,引入了UV后,就能更精确的统计。
总结:
UV的统计数比IP更为准确,能够准确的计数每一台访问电脑,而IP把同一局域内的所有电脑视为一个。
(PS:UV计数会涉及COOKIE。)
上次因工作的需求对一台apache的log做了一次整体的分析,所以顺便也对apache的日志分析做下简单的介绍,主要参考apache官网的Log Files,手册参照 http://httpd.apache.org/docs/2.2/logs.html
一.日志分析
如果apache的安装时采用默认的配置,那么在/logs目录下就会生成两个文件,分别是access_log和error_log
1.access_log
access_log为访问日志,记录所有对apache服务器进行请求的访问,它的位置和内容由CustomLog指令控制,LogFormat指令可以用来简化该日志的内容和格式
例如,我的其中一台服务器配置如下
CustomLog “| /usr/sbin/rotatelogs /var/log/apache2/%Y_%m_%d_other_vhosts_access.log 86400 480″ vhost_combined
-rw-r–r– 1 root root 22310750 12-05 23:59 2010_12_05_other_vhosts_access.log
-rw-r–r– 1 root root 26873180 12-06 23:59 2010_12_06_other_vhosts_access.log
-rw-r–r– 1 root root 26810003 12-07 23:59 2010_12_07_other_vhosts_access.log
-rw-r–r– 1 root root 24530219 12-08 23:59 2010_12_08_other_vhosts_access.log
-rw-r–r– 1 root root 24536681 12-09 23:59 2010_12_09_other_vhosts_access.log
-rw-r–r– 1 root root 14003409 12-10 14:57 2010_12_10_other_vhosts_access.log
通过CustomLog指令,每天一天生成一个独立的日志文件,同时也写了定时器将一周前的日志文件全部清除,这样可以显得更清晰,既可以分离每一天的日志又可以清除一定时间以前的日志通过制,LogFormat定义日志的记录格式
LogFormat “%h %l %u %t \”%r\” %>s %b \”%{Referer}i\” \”%{User-Agent}i\”” combined
LogFormat “%{X-Forwarded-For}i %l %u %t \”%r\” %>s %b \”%{Referer}i\” \”%{User-Agent}i\”” combinedproxy
LogFormat “%h %l %u %t \”%r\” %>s %b” common
LogFormat “%{Referer}i -> %U” referer
LogFormat “%{User-agent}i” agent
随意的tail一个access_log文件,下面是一条经典的访问记录
218.19.140.242 – – [10/Dec/2010:09:31:17 +0800] “GET /query/trendxml/district/todayreturn/month/2009-12-14/2010-12-09/haizhu_tianhe.xml HTTP/1.1″ 200 1933 “-” “Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 (.NET CLR 3.5.30729)”
一共是有9项,将他们一一拆开
218.19.140.242


[10/Dec/2010:09:31:17 +0800]
“GET /query/trendxml/district/todayreturn/month/2009-12-14/2010-12-09/haizhu_tianhe.xml HTTP/1.1″
200
1933
“-”
“Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 (.NET CLR 3.5.30729)”
1) 218.19.140.242 这是一个请求到apache服务器的客户端ip,默认的情况下,第一项信息只是远程主机的ip地址,但我们如果需要apache查出主机的名字,可以将 HostnameLookups设置为on,但这种做法是不推荐使用,因为它大大的减缓了服务器.另外这里的ip地址不一定就是客户主机的ip地址,如果 客户端使用了代理服务器,那么这里的ip就是代理服务器的地址,而不是原机.
2) – 这一项是空白,使用”-”来代替,这个位置是用于标注访问者的标示,这个信息是由identd的客户端存在,除非IdentityCheck为on,非则apache是不会去获取该部分的信息(ps:不太理解,基本上这一项都是为空,奉上原文)
The “hyphen” in the output indicates that the requested piece of information is not available. In this case, the information that is not available is the RFC 1413 identity of the client determined by identd on the clients machine. This information is highly unreliable and should almost never be used except on tightly controlled internal networks. Apache httpd will not even attempt to determine this information unless IdentityCheck is set to On.
3) – 这一项又是为空白,不过这项是用户记录用户HTTP的身份验证,如果某些网站要求用户进行身份雁阵,那么这一项就是记录用户的身份信息
4) [10/Dec/2010:09:31:17 +0800] 第四项是记录请求的时间,格式为[day/month/year:hour:minute:second zone],最后的+0800表示服务器所处的时区为东八区
5) “GET /..haizhu_tianhe.xml HTTP/1.1″ 这一项整个记录中最有用的信息,首先,它告诉我们的服务器收到的是一个GET请求,其次,是客户端请求的资源路径,第三,客户端使用的协议时HTTP/1.1,整个格式为”%m %U%q %H”,即”请求方法/访问路径/协议”
6) 200 这是一个状态码,由服务器端发送回客户端,它告诉我们客户端的请求是否成功,或者是重定向,或者是碰到了什么样的错误,这项值为200,表示服务器已经成 功的响应了客户端的请求,一般来说,这项值以2开头的表示请求成功,以3开头的表示重定向,以4开头的标示客户端存在某些的错误,以5开头的标示服务器端 存在某些错误,详细的可以参见 HTTP specification (RFC2616 section 10).[http://www.w3.org/Protocols/rfc2616/rfc2616.txt]
7) 1933 这项表示服务器向客户端发送了多少的字节,在日志分析统计的时侯,把这些字节加起来就可以得知服务器在某点时间内总的发送数据量是多少
8) – 暂不知
9) “Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 (.NET CLR 3.5.30729)” 这项主要记录客户端的浏览器信息
2.error_log
error_log为错误日志,记录下任何错误的处理请求,它的位置和内容由ErrorLog指令控制,通常服务器出现什么错误,首先对它进行查阅,是一个最重要的日志文件
tail error_log,随意摘取一个记录
[Fri Dec 10 15:03:59 2010] [error] [client 218.19.140.242] File does not exist: /home/htmlfile/tradedata/favicon.ico
同样也是分为几个项
[Fri Dec 10 15:03:59 2010]
[error]
[client 218.19.140.242]
File does not exist: /home/htmlfile/tradedata/favicon.ico
1) [Fri Dec 10 15:03:59 2010] 记录错误发生的时间,注意,它跟我们上面access_log记录的时间格式是不同的
2) [error] 这一项为错误的级别,根据LogLevel指令来控制错误的类别,上面的404是属于error级别
3) [client 218.19.140.242] 记录客户端的ip地址
4) File does not exist: /home/htmlfile/tradedata/favicon.ico 这一项首先对错误进行了描述,例如客户端访问一个不存在或路径错误的文件,就会给出404的提示错误
二.实用的日志分析脚本
了解日志的各种定义后,这里分享一下从网上淘来的一些对日志分析的脚本
1.查看apache的进程数
ps -aux | grep httpd | wc -l
2.分析日志查看当天的ip连接数
cat default-access_log | grep “10/Dec/2010″ | awk ‘{print $2}’ | sort | uniq -c | sort -nr
3.查看指定的ip在当天究竟访问了什么url
cat default-access_log | grep “10/Dec/2010″ | grep “218.19.140.242″ | awk ‘{print $7}’ | sort | uniq -c | sort -nr
4.查看当天访问排行前10的url
cat default-access_log | grep “10/Dec/2010″ | awk ‘{print $7}’ | sort | uniq -c | sort -nr | head -n 10
5.看到指定的ip究竟干了什么
cat default-access_log | grep 218.19.140.242 | awk ‘{print $1″\t”$8}’ | sort | uniq -c | sort -nr | less
6.查看访问次数最多的几个分钟(找到热点)
awk ‘{print $4}’ default-access_log |cut -c 14-18|sort|uniq -c|sort -nr|head
三.使用awstats自动分析日志
当然啦,如果想最简单和最直观的分析日志还是用工具,现在网上较流行的工具是awstats,一个基于perl的web日志分析工具,功能很强大也支持IIS等服务器

Apache如何每天生成独立日志文件(access_log和error_log)

apache运行自动生成access_log(访问日志)和error_log(错误日志)两种日志文件,这对于系统管理员或网站运营人员是非常有用的。
我安装的是centos,使用yum方式安装lamp环境的,日志文件位置:
/var/log/httpd/access_log是Apache服务器的访问日志文件
/var/log/httpd/error_log是Apache服务器的错误日志文件
如果把所有的访问日志都放在access_log,所有的错误日志都放在error_log文件,那么着两个文件肯定会很大,你打开日志的时间都会很长,别说看了,而且影响网站速度。我看了下php点点通,刚转到阿里云才几天,日志文件都有几十兆了,因此限制日志文件大小是很有必要的。
打开apache的配置文件:vi /etc/httpd/conf/httpd.conf
编辑:
#错误日志
#ErrorLog logs/error_log #注释,加上下面这行
ErrorLog “|rotatelogs /var/log/httpd/error_log%Y_%m_%d.log 86400 480” #每天生成错误日志
#访问日志
#CustomLog logs/access_log common #注释加上下面这样
CustomLog “|rotatelogs /var/log/httpd/access_log%Y_%m_%d.log 86400 480″ common #每天生成访问日志
OK,重启apache,你就可以看到新生成的日志文件:
Apache如何每天生成独立日志文件(access_log和error_log)
Rotatelogs的用法如下:

rotatelogs [ -l ] logfile [ rotationtime [ offset ]] | [ filesizeM ]
选项:
-l
使用本地时间代替GMT时间作为时间基准。注意:在一个改变GMT偏移量(比如夏令时)的环境中使用-l会导致不可预料的结果。
logfile
它加上基准名就是日志文件名。如果logfile中包含”%”,则它会被视为用于strftime()的格式字符串;否则它会被自动加上以秒为单位的”.nnnnnnnnnn”后缀。这两种格式都表示新的日志开始使用的时间。
rotationtime
日志文件滚动的以秒为单位的间隔时间。
offset
相对于UTC的时差的分钟数。如果省略,则假定为”0″并使用UTC时间。比如,要指定UTC时差为”-5小时”的地区的当地时间,则此参数应为”-300″。
filesizeM
指定以filesizeM文件大小滚动,而不是按照时间或时差滚动。
转载请注明地址: http://www.phpddt.com/server/apache-access-error-log.html 尊重他人劳动成果就是尊重自己!

如何分析apache日志[access_log(访问日志)和error_log(错误日志)]

默认Apache运行会access_log(访问日志)和error_log(错误日志)两个日志文件。
看一条典型的access_log的日志记录:
61.155.149.20 – – [17/Dec/2013:05:42:47 +0800] “GET /category/db/ HTTP/1.1″ 200 23225
1)61.155.149.20 这是一个请求到apache服务器的客户端ip,默认的情况下,第一项信息只是远程主机的ip地址,但我们如果需要apache查出主机的名字,可以将 HostnameLookups设置为on,不推荐使用,会大大降低网站速度。

2) – 这一项是空白,使用”-“来代替,用于记录浏览者的标识,对于大多数浏览器,这项都是空。

3) – 也为空,记录浏览者进行身份验证时提供的名字,大多数这项也为空。

4) [17/Dec/2013:05:42:47 +0800]第四项是记录请求的时间,格式为[day/month/year:hour:minute:second zone],最后的+0800表示服务器所处的时区为东八区

5) “GET /category/db/ HTTP/1.1″ 这一项最有用,首先,它告诉我们的服务器收到的是一个GET请求,其次,是客户端请求的资源路径,第三,客户端使用的协议时HTTP/1.1,整个格式为”%m %U%q %H”,即”请求方法/访问路径/协议”

6) 200 这是一个状态码,由服务器端发送回客户端,它告诉我们客户端的请求是否成功,或者是重定向,或者是碰到了什么样的错误,这项值为200,表示服务器已经成 功的响应了客户端的请求,一般来说,这项值以2开头的表示请求成功,以3开头的表示重定向,以4开头的标示客户端存在某些的错误,以5开头的标示服务器端 存在某些错误。

7) 23225 这项表示服务器向客户端发送了多少的字节,在日志分析统计的时侯,把这些字节加起来就可以得知服务器在某点时间内总的发送数据量是多少

再来看一条error_log信息:
[Tue Dec 17 02:22:46 2013] [error] [client 61.182.137.33] File does not exist: /var/www/html/usr/themes/dddefault/all.txt
1) [Tue Dec 17 02:22:46 2013] 记录错误发生的时间,注意,它跟我们上面access_log记录的时间格式是不同的
2) [error] 这一项为错误的级别,根据LogLevel指令来控制错误的类别,上面的404是属于error级别
3) [client 61.182.137.33] 记录客户端的ip地址
4) File does not exist: /var/www/html/usr/themes/dddefault/all.txt 错误描述。

转载请注明地址: http://www.phpddt.com/server/apache-log.html 尊重他人劳动成果就是尊重自己!

Mac OS X 10.10 Yosemite下面解决XAMPP无法开启mysql的问题

在xampp安装目录下找到xamp这个文件(默认路径是:/Applications/XAMPP/xamppfiles/xampp)
用文本编辑器打开,搜索:$XAMPP_ROOT/bin/mysql.server start > /dev/null &
在那一行前面添加: unset DYLD_LIBRARY_PATH
保存退出,重新打开xampp,开启MySQL。
卧槽,居然变绿了,成功了