4月 242010
 

原来听说使用script标签动态加载js时,加载源不能做gzip压缩,今天测试了一下,没这回事儿,不管ff和ie都没有这回事儿。
顺便了解了一下怎样在Apache2下开启gzip压缩。

        

  1. # 加载deflate模块
  2.     

  3. LoadModule deflate_module modules/mod_deflate.so
  4.     

  5. # 设置压缩频率,取值范围在 1(最低压缩率) 到 9(最高压缩率)之间
  6.     

  7. # 不建议设置太高,虽然有很高的压缩率,但是占用更多的CPU资源
  8.     

  9. DeflateCompressionLevel 3
  10.     

  11. # Compress everything except images
  12.     

  13. <Location />
  14.     

  15. # 插入过滤器
  16.     

  17. SetOutputFilter DEFLATE
  18.     

  19.  
  20.     

  21. # Netscape 4.x 有一些问题…
  22.     

  23. BrowserMatch ^Mozilla/4 gzip-only-text/html
  24.     

  25. # Netscape 4.06-4.08 有更多的问题
  26.     

  27. BrowserMatch ^Mozilla/4\.0[678] no-gzip
  28.     

  29. # MSIE 会伪装成 Netscape ,但是事实上它没有问题
  30.     

  31. BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
  32.     

  33. # 不压缩图片
  34.     

  35. SetEnvIfNoCase Request_URI \\.(?:gif|jpe?g|png)$ no-gzip dont-vary
  36.     

  37. </Location>
 Posted by at 下午 12:13
4月 102010
 

当apache监听多个端口或多个ip上的端口时,多个子进程是怎么分工的呢?和只监听一个端口有什么区别吗?

1. 如果apache的多个进程只监听一个端口,则不需要AcceptMutex,每个apache进程都在执行accept操作,发现请求后就开始执行,执行完继续accept,多个进程之间不会相互干扰,这是由accept的机制来完成的。

2. 如果apache的多个进程只监听socket多于一个,则不能直接accept了,就必须使用select或poll机制来发现知否有请求需要执行,发现之后,再由accept来接受请求;然而select或poll没有accept那么能自动处理互斥的问题,这时候就需要一个“锁”了,就是所谓的AcceptMutex,AcceptMutex的实现形式有多种,这个不属于本文讨论的范围。
   下面是apache在监听三个socket(
[16 17 18])时,其中一个进程的表现:
semop(524288, 0x81dd334, 1)             = 0
select(19, [16 17 18], NULL, NULL, NULL) = 1 (in [17])
accept(17, {sa_family=AF_INET, sin_port=htons(52932), sin_addr=inet_addr("10.55.38.9")}, [16]) = 29
semop(524288, 0x81dd33a, 1)             = 0

第一步:先获取锁(0x81dd334), 同一时刻只有一个进程能获取锁
第二步:开始select(对于apache2这里好像是poll,poll的效率更高一些),并且发现17需要处理了
第三步:accept 17
第四步:释放锁,这样其它进程就可以获取锁并处理后续的请求了

 Posted by at 上午 7:32
10月 072009
 

公共网关界面CGI目前在实际应用中最广,本文介绍了客户机、服务器和CGI Script之间如何进行通信和共享信息,了解这些内容有助于用户编写自己的CGI Script。

公共网关界面CGI是一种在服务器与外部Script(脚本程序)或程序之间进行交互的方法。该界面确切地说是一个网关,它通过从服务器上接收信息,并创建一个子过程,用于为CGI Script处理或存储这部分信息。

CGI能使用户在自己的Web页面上添加一些程序,这样访问者就能与该Web页面进行交互检索实时信息,与其它访问者进行交互等。

利用CGI用户可以向网站的访问者提供一种方法以访问你的数据库、存储信息和执行一些外部程序(例如发送电子邮件等)。CGI有助于将Web页面从简单 地提供静态信息转变为提供实时或动态信息。在没有CGI时,我们只能将网页放到Web上供访问者阅读。对于网页的改变,通常只能采用手工方法来重写每个语 句的HTML代码,以保证信息的及时更新。有了CGI,就可以通过创建Script来与数据库进行交互,向用户及时提供任何一个更新阶段的信息,而这些相 对于CGI为你或单位所能提供的帮助而言只不过是一个小应用。

那么,CGI是如何在客户机与服务器之间进行工作的?

CGI如何工作

服务器根据客户机在进行请求时所采用的方法,收集由客户机提供的信息,并将该部分信息发送给CGI Script。然后CGI Script进行信息处理并将结果返回服务器。服务器再对信息进行分析,最后将结果发送给客户机,流程如图1。


客户机通过使用GET、POST或HEAD方法来调用Script。而将信息提供给Script的途径则取决于所使用的方法。通常GET和POST方法,在CGI Script中比HEAD方法要用得多一些。

1、环境变量

在提出请求或调用CGI Script时,客户机和服务器要将部分信息保存在某些环境变量中,而服务器和Script都能够使用这些变量。环境变量分为三类:服务器信息、客户机信息和Script信息,这里简要地说明每类变量的大致功能和作用。

服务器信息变量:服务器提供了在用户的Script中所要用到的关于服务器本身的信息。这部分信息包括有服务器软件和所用软件的版本号、服务器名称、服务器采用的协议和协议的版本号以及服务器端口号和网关界面。

客户机信息变量:同服务器一样,客户机也要提供一些自身的信息。客户机变量能够提供有关访问本网站的访问者的信息,如访问者所使用的Web浏览器名称、 访问者来自何处等。该信息中还可能包括访问者的IP地址、访问者所在网站的域名,以及当访问的页面被口令保护时要求用名和口令。

Script信息变量:在表单(Form)和Script中也要由变量来表示信息。例如在你的表单中含有由服务器接收到的信息,服务器将这些信息保存到环 境变量中,这样你的CGI Script就可以方便地使用这些信息了。在Script信息变量中,常见的变量有QUERY-STRING(含有访问者输入的信息)、CONTENT- TYPE(告知服务器接收哪一类的信息)、CONTENET-LENGTH(用户输入信息的长度)等。

2、命令行方式

在CGI Script中允许使用命令行方式,而只有带有〈ISINDEX〉属性进行查询(query)才能使用命令行。在一个查询串中,当使用不带等号(=)的〈ISIN DEX〉标签时,服务器允许你对系统发送一个查询命令,然后返回查询结果。

在制定HTTP规则时,该方法被认为是安全的,但在以后的使用中出现了一些问题,例如有关获得对本网站根目录的访问权限问题。因此,用户最好在必要时才使用该方法。

3、STDIN和STDOUT

每个程序都有STDIN(标准输入)和STDOUT(标准输出)。CGI的STDIN是服务器的STDOUT。CGI程序先对某信息进行处理,然后将结 果送到STDOUT。服务器通过它的STDIN接收到结果,再通过它的STDOUT把结果发送给客户机, 这个流程如图2所示。

4、GET方法

在进行简单查询时,当查询串长度小于255个字符,GET方法是一种最常用的方法。具体使用GET方法是将某个查询串放到环境变量QUERY- STRING中,该变量长度限制在255个字符内,包括空格。在查询中,当“?”标记之后是一个查询串时,服务器便会创建一个环境变量QUERY- STRING,并把该查询串放到该变量中。

5、POST方法

POST方法也可以使用环境变量,但该方法向CGI Script发送的多数信息都是通过STDIN和STDOUT。

 
在POST方法应用中,当访问者使用表单向服务器发送信息时,信息先被送到服务器的STDOUT,继而进入CGI Script的STDIN。Script必然对信息进行解码和处理,然后将结果送至STDOUT。POST方法在CGI编程中是最常使用方法。

CGI Script 使用的语言

可以使用任何一种编程语言来编写CGI Script。作为用户来说,采用哪一种变成语言完全取决于编程者的应用方向和对语言的熟悉程度。

Perl:Practical Extraction and Report Language,实用提取与报表语言,可以说它在众多的CGI编程中最流行。Perl语言的语法规则简单,很容易学习,比C语言、Tcl或其他的语言容 易掌握,而且,可以用于UNIX、Windows NT、95、OS 2/Warp 和VMS以及Macintosh 和Amiga。(http://www.perl.com/perl/) 语言:是一种最常使用的编程语言,它在CGI 编程中也发挥得很出色。C语言比Perl难学,但是 C 语言程序运行速度快,并且由于C语言很灵活,因此用户几乎可以做任何事情。C 语言的一个缺点是C代码难以调试,在C程序中稍有任何改动,都要对源程序重新进行编译。因此,在C编程时,对于要求简单并且迅速的Script来说,经常 改动是麻烦的问题。

UNIX Shell:提供了用于创建简单、运行快的CGI Script的一种方法。当然,你也可以使用shell来创建相当复杂的Script,但是那样做所付出的代价非常大。而shell对于编写一些小的 Script来说是非常有效的。如果已经熟悉了UNIX,那么UNIX shell能够使你通过使用系统命令来处理查询信息,使创建Script变得十分简单。

TCL 语言: Tool Command Language,工具命令语言主要用于MS-DOS、Macintosh和UNIX系统。如果对C语言熟悉,学习TCL很容易,因为TCL的语法规则类 似于C语言。就编写CGI Script而言,TCL语言还没有像其它语言那样普及,但是它的发展速度却很快。此外,TCL语言的可移植性不是很好,因为它能使用直接的系统调用,而 这些调用往往都是计算机特定的。

Visual Basic 语言:它是创建CGI script的一种优秀语言。该语言易于学习,对初学者来说是一个比较好的选择。在CGI应用中,Visual Basic算是一个较新的语言,但是它在Internet中已经越来越多的被引入到Windows NT和Windows95的Web服务器上。Visual Basic是能够编译的BASIC编程语言,尽管没有C语言运行快,但它有一个非常显著的优点,即它在Microsoft操作系统上非常流行。

Java语言:它能够用来创建一个称为applet(小程序)的程序,浏览器以二进制方式接收到applet并能够执行它,这要求浏览器能够运行applet。

C++:是另外一种可以用来编写CGI Script的语言,C++是一个面向对象的编程语言,通过使用部分的C++源代码可以使CGI的开发变得比较容易和减少冗余。

AppleScript:广泛用在基于Macintosh的Web服务器上。该语言非常容易理解,对于一些小的应用程序来说其功能是足够强的。

CGI的未来

目前的CGI规则中有一些内在的问题,原因是在一个Web服务器上的某个CGI Script是作为一个分离的进程,而非常拥挤的网站可能会超负荷。尽管在Web服务器上,CGI是一种运行外部程序功能最强大的方法,但仍有一些方面需要提高。

一些组织已经开始编写不同的API规则,力图开发出好的方案来解决上面的问题:

FastCGI是另一个很有希望的CGI解决方案,由Open Market开放。FastCGI提供了一种方法,能够提高服务器与外部程序通信的速度,在执行CGI操作时减少服务器上的负担。FastCGI的特点是 与语言无关,与服务器无关。FastCGI的设计能够使它的程序运行在外部服务器上,放宽了对服务器系统的要求,而是主要集中在HTTP请求和执行用户身 份的认证及检查上。(http://www.fastcgi.com)

ILU Requestor的设计也是用于解决相同的问题,即CGI的高负荷和较慢的响应时间问题,尤其是在一个很忙的服务器上。ILU Requestor与具体语言无关,具有可移植和运行速度快的特点。(http://www.w3.org/hypertext/WWW/TR/WD- ilu-requestor)

ISAPI(Internet Server Application Programming Interface)由Process Software和Microsoft公司共同开发,是比较有希望能够取代CGI的API接口,特别是那些基于Windows的Web服务器。ISAPI 设计的基本思想是基于动态链接库DLL,使得后台程序运行速度提高。

 Posted by at 下午 7:46
7月 122009
 

关于apache中的异常:

现象:
1、 10.49.4.61 的httpd访问不了,但是访问却又不是立即退出,而是一直等待
2、 10.49.4.61 的httpd子进程240个,不再变化
3、 netstat 发现很多close_wait 的连接; 就是客户端已经断开,但是服务器还没有断开的情况 

分析:
1. tcpdump 发现连接已建立,也发送了一些请求数据,接着就什么也没有了; 说明请求并没有被apache子进程给接走
2. netstat 查看一下,发现Recv-Q 里面确实有数据
3. strace httpd子进程发现每个子进程都如下:
 write(11, "10.49.4.21 – – [12/Jul/2009:10:2"…, 101 <unfinished …>

 显然,要写apache日志,而且是今天10点20多时的日志,但是被某种原因给阻塞了,下面就是要知道为什么阻塞了
4. 看一下fd = 11 是个什么东西:
 [root@sso115 htdocs]# ll /proc/17151/fd/
 total 0
 lr-x—— 1 root root 64 Jul 12 10:53 0 -> /dev/null
 l-wx—— 1 root root 64 Jul 12 10:53 1 -> /dev/null
 lr-x—— 1 root root 64 Jul 12 10:53 10 -> eventpoll:[41846266]
 l-wx—— 1 root root 64 Jul 12 10:53 11 -> pipe:[41551707]
 lrwx—— 1 root root 64 Jul 12 10:53 12 -> socket:[41846267]
 l-wx—— 1 root root 64 Jul 12 10:53 13 -> pipe:[41551708]
 l-wx—— 1 root root 64 Jul 12 10:53 2 -> /data1/apache2/logs/error_log
 lrwx—— 1 root root 64 Jul 12 10:53 3 -> socket:[39585452]
 lrwx—— 1 root root 64 Jul 12 10:53 4 -> socket:[39585453]
 lr-x—— 1 root root 64 Jul 12 10:53 5 -> pipe:[41551704]
 l-wx—— 1 root root 64 Jul 12 10:53 6 -> pipe:[41551704]
 l-wx—— 1 root root 64 Jul 12 10:53 7 -> /data1/apache2/logs/access_log
 l-wx—— 1 root root 64 Jul 12 10:53 8 -> pipe:[41551705]
 l-wx—— 1 root root 64 Jul 12 10:53 9 -> pipe:[41551706]

 原来是个管道,可能是管道写满了;那么这个管道是做什么的呢?

5. 应该是和rotatelogs程序共有的pipe,验证如下:
 rotatelogs 只剩下三个进程了,应该有四个呢,肯定被谁误杀了一个!!!
 [root@sso115 ~]# ps aux | grep rot                    
 root     29709  0.0  0.0  61116   736 pts/1    S+   14:04   0:00 grep rot
 root     31469  0.0  0.0  23524   696 ?        S    Jul10   0:00 /data1/apache2/bin/rotatelogs /data1/apache2/logs/%Y%m/online.internal.sina.com.cn-80-error_log.%Y%m%d 86400 480
 root     31470  0.0  0.0  23524   692 ?        S    Jul10   0:00 /data1/apache2/bin/rotatelogs /data1/apache2/logs/%Y%m/online.sso.sina.com.cn-80-error_log.%Y%m%d 86400 480
 root     31472  0.0  0.0  23524   692 ?        S    Jul10   0:00 /data1/apache2/bin/rotatelogs /data1/apache2/logs/%Y%m/online.sso.sina.com.cn-80-access_log.%Y%m%d 86400 480
 [root@sso115 ~]#
 
 每个进程里面都没有这个管道
 [root@sso115 ~]# ll /proc/31469/fd
 total 0
 lr-x—— 1 root root 64 Jul 12 10:53 0 -> pipe:[41551705]
 l-wx—— 1 root root 64 Jul 12 10:53 1 -> /dev/null
 l-wx—— 1 root root 64 Jul 12 10:53 2 -> /data1/apache2/logs/error_log

 [root@sso115 ~]# ll /proc/31470/fd
 total 0
 lr-x—— 1 root root 64 Jul 12 10:53 0 -> pipe:[41551706]
 l-wx—— 1 root root 64 Jul 12 10:53 1 -> /dev/null
 l-wx—— 1 root root 64 Jul 12 10:53 2 -> /data1/apache2/logs/error_log
 [root@sso115 ~]#

 [root@sso115 ~]# ll /proc/31472/fd
 total 0
 lr-x—— 1 root root 64 Jul 12 10:53 0 -> pipe:[41551708]
 l-wx—— 1 root root 64 Jul 12 10:53 1 -> /dev/null
 l-wx—— 1 root root 64 Jul 12 10:53 2 -> /data1/apache2/logs/error_log
 [root@sso115 ~]#

 显然,那个rotatelogs进程肯定是被谁给杀掉了,或者是出现意外死亡了;
 查了一下系统log,有看了一下用户的.bash_history 都没有发现和rotatelogs相关的信息

6. 没法查下去了,不过可以做一个测试,就是把rotatelogs进程杀掉,是否就肯定出现这种现象
 使用graceful的办法重启apache,原以为不能凑效,因为请求都是为处理完的,而且不可能处理完的;但是还是都死掉了

7. 重启apache,两个虚拟机,四个rotatelogs 进程; 试图杀死一个rotatelogs进程,但总是立即又出现了一个新的,以为该进程具有自派生机制,
 就用 kill -9 来杀,结果还是立即重新启动一个;
 观察了一下新的进程的ppid,发现时apache守护进程的pid,于是用strace监视一下apache的守护进程; 因为rotatelogs 进程是apache守护
 进程的子进程,所以rotatelogs进程死掉的时候会给apache守护进程发送一个信号,apache守护进程就可以根据自己保存的管道在启动一个
 rotatelogs进程,于是这个进程就有了杀不死的功能了。
 可以用这个办法做杀不死进程。
 
 跟踪apache守护进程的主要信息
 22934 14:34:35.057195 wait4(-1, [{WIFSIGNALED(s) && WTERMSIG(s) == SIGKILL}], WNOHANG|WSTOPPED, NULL) = 31358
 22934 14:34:35.057365 write(2, "piped log program \’/data1/apache"…, 154) = 154
 22934 14:34:35.057490 dup(10)           = 14
 22934 14:34:35.057561 dup(11)           = 15
 22934 14:34:35.057619 dup(1)            = 16
 22934 14:34:35.057689 dup(2)            = 17
 22934 14:34:35.057893 access("/data1/apache2/bin/rotatelogs", X_OK) = 0
 22934 14:34:35.057991 clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x2aaaab123c70) = 31463

 Posted by at 上午 1:12
6月 242009
 

曾经修改过/etc/resolve.conf后,发现apache进程里还是使用旧的dns server来解析域名,重启apache后才生效;这里给出几个确认的办法:

办法一: 如果服务器上没有其它需要域名解析的进程的话,使用tcpdump 来观察53端口的udp包就基本可以知道了

                  命令: tcpdump -i eth1 -nn -X -s 0  "port 53 and udp"

办法二: 随便找一个httpd的子进程strace一下就基本知道了,但是要求两点:

                  1. 访问量比较大,随时都有做域名解析的可能;而且程序里确实有做域名解析的需要

                   2. httpd子进程不会死的太快,太快了你会抓不到的

                  命令: strace -p pid_of_httpd_child -e trace=network 2>&1 | grep "(53)"

办法三: 因为httpd子进程可能死的太快,我们就从httpd的守护进程着手
                 命令: strace -p pid_of_httpd_parent -fF -e trace=network 2>&1 | grep "(53)"

 Posted by at 下午 10:05
6月 062009
 

1. ab 、 webbench 、http_load的特点
这些测试工具都是单进程、非线程的程序,它的并发是通过异步实现的,虽然也实现的并发,就是说,同时确实存在着n个并发,但是需要注意的是,对于一个非常简单的接口来讲,客户端要做的事情和服务器端要做的事情差不太多;这时,一个单进程的程序去压一个多进程的程序,显然客户端可能一直忙于发请求,接受响应,而服务器端却很清闲,甚至n/3个httpd子进程就可以搞定n个并发了,这就是为什么n个并发,而服务器端的httpd子进程数却远小于n的可能的原因之一。

2. siege
siege 是一个单进程多线程的程序,只是测试结果数据太少,不太能说明问题

3. 尽管如此,我们还是可以用ab做多进程的并发的,如下:

for i in seq 1 50;do  nohup /data1/apache/bin/ab -n 10000 -c 1 "http://10.20.30.40/test.php" >ab.$i.txt &;done

这就是一个并发50,总数50万的ab压力测试

 Posted by at 下午 12:53
6月 052009
 

你的服务器是否打开了keep-alive 呢?看看httpd.conf 就知道了,但是也不是必须的,简单测试一下就知道了,用第三个请求比较稳妥一些,看看下面的几个请求,顺便理解一下HTTP/1.0  与 HTTP/1.1 的几个区别:

请求1:
———————————-
GET / HTTP/1.1
Host: phpor.net

返回结果的编码格式:Transfer-Encoding: chunked
没有立即关闭连接,说明:HTTP/1.1 默认支持(启用)keep-alive

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

请求2:
———————————-
GET / HTTP/1.0
Host: pengyou.sina.com.cn
Connection: Keep-Alive

返回结果的编码格式:Content-Length: 5556       说明: HTTP/1.0 还不支持Transfer-Encoding: chunked的传输编码方式
没有立即关闭连接,说明:HTTP/1.0 也可以使用 keep-alive
———————————-

请求3:
———————————-
GET / HTTP/1.1
Host: phpor.net
Connection: Keep-Alive

这个就肯定keep-alive了
———————————-

请求4:
———————————-
GET / HTTP/1.0
Host: phpor.net

这个请求就;
1. 不能Transfer-Encoding: chunked
2. 不能keep-alive
———————————-

结论:
要了解某个server是否打开了keep-alive ,只需用telnet发一个类似于前三种的请求,看看是否立即关闭了就行了

 Posted by at 上午 7:43
4月 182009
 

关于apache模块的资料比较少,这里给出两个比较简单的例子,来揭开apache模块神秘的面纱,当然例子很初级,不过只有初级才容易入门,写一个helloworld吧:

/**
 * filename:    helloworld.c
 * author:      lijunjie <lijunjie1982@yahoo.com.cn>
 * version:     1.0
 */
#include <httpd.h>
#include <http_protocol.h>
#include <http_config.h>

static int helloworld_handler(request_rec *r) {
        if (!
r->handler || strcmp(r->handler"helloworld"
)) {
                return 
DECLINED
;
        }
        if (
r->method_number != M_GET
){
                return 
HTTP_METHOD_NOT_ALLOWED
;
        }
        
ap_set_content_type(r,"text/html;charset=asscii"
);
        
ap_rputs("hello world"r
);
        return 
OK
;
}

static void helloworld_hooks(apr_pool_t *pool) {
        
ap_hook_handler(helloworld_handlerNULLNULLAPR_HOOK_MIDDLE
);
}

module AP_MODULE_DECLARE_DATA helloworld_module = {
        
STANDARD20_MODULE_STUFF
,
        
NULL
,
        
NULL
,
        
NULL
,
        
NULL
,
        
NULL
,
        
helloworld_hooks
};

/****** install ***********
compile: apxs -i -c mod_helloworld.c

modify httpd.conf, add

LoadModule helloworld_module modules/mod_helloworld.so

<Location /helloworld>
    SetHandler helloworld
</Location>

********************************/

 

下面给出一个稍微复杂一点的,对我们进一步的了解有很大帮助的,它可以输出一些比较有意义的东西了

/**
 * filename:    helloworld.c
 * author:      lijunjie <lijunjie1982@yahoo.com.cn>
 * version:     1.1
 */
#include <httpd.h>
#include <http_protocol.h>
#include <http_config.h>

static int printitem(void *rec, const char *key, const char *value){
        
// recive rec pointer , we will send  some request use it
        
request_rec *rec;
        
ap_rprintf(r"<tr><th scope=’row’>%s</th><td>%s</td></tr>\n"
                                        
ap_escape_html(r->poolkey), 
                                        
ap_escape_html(r->poolvalue));
        return 
1;
}

static void printtable(request_rec *rapr_table_t *t
                                const 
char *caption, const char *keyhead,
                                const 
char *valhead) {
                
ap_rprintf(r,"<table border=’1′ width=’100%’><caption>%s</caption><thead>"
                                                "<tr><th scope=’col’>%s</th><th scope=’col’>%s"
                                                "</th></tr></thead><tbody>"
,
                                                 
captionkeyheadvalhead);
                
apr_table_do(printitemrtNULL);

                ap_rputs("</tbody></table>\n",r);

}
static int helloworld_handler(request_rec *r) {
        if (!
r->handler || strcmp(r->handler"helloworld")) {
                return 
DECLINED;
        }
        if (
r->method_number != M_GET){
                return 
HTTP_METHOD_NOT_ALLOWED;
        }
        
ap_set_content_type(r,"text/html;charset=asscii");
        
ap_rputs("This is the Apache hello world module<br>"r);
        
printtable(rr->headers_in"Request Headers""Header""Value");
        
printtable(rr->headers_out"Response Headers""Header""Value");
        
printtable(rr->headers_in"Environment""Variable""Value");

        return OK;
}

static void helloworld_hooks(apr_pool_t *pool) {
        
ap_hook_handler(helloworld_handlerNULLNULLAPR_HOOK_MIDDLE);
}

module AP_MODULE_DECLARE_DATA helloworld_module = {
        
STANDARD20_MODULE_STUFF,
        
NULL,
        
NULL,
        
NULL,
        
NULL,
        
NULL,
        
helloworld_hooks
};
/****** install ***********
compile: apxs -i -c mod_helloworld.c

modify httpd.conf, add

LoadModule helloworld_module modules/mod_helloworld.so

<Location /helloworld>
    SetHandler helloworld
</Location>

********************************/

 Posted by at 上午 4:39
4月 032009
 

日志格式:
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\""

实时查看:
tail -f access_log | awk -F"[" ‘{print $2}’ | awk -F"]" ‘{print $1}’ | uniq -c
结果显示每秒的访问量,如果只关心某个接口,添加grep就行了

按天统计:
cat access_log.20090401 | php -R ‘preg_match("/(GET|POST){1} (\/[^? ]+)/",$argn, $matches);$arr[$matches[2]]++; $sum++;’ -E ‘foreach($arr as $key=>$val) echo $val . "\t" . $val/$sum*100 ."%\t". $key ."\n"; echo "total\t$sum";’ |sort -nr

统计查询字符串里面的某个参数:

cat access_log.20090401 | php -R ‘preg_match("/(GET|POST) [^\"]*entry=([^& ]*)[&
]?/",$argn,$matches);echo $matches[2]."\n";’ | sort -n | uniq -c | sort -rn


匹配2009-08-27~29 三天的日志,用户名以 _[0-9a-z]{5} 结尾:

grep  space /data2/ssologs/login/200908/*2[7-9] | grep "| LoginFlow |" | grep "| 2 |" | grep credentail |  awk -F "|"  –posix ‘$6 ~ / [^_]+_[0-9a-z]{5} $/’

注意: 这里的 {} 属于posix的正则,需要选项 –posix

 

 Posted by at 上午 1:12