自制 Apache 日志分析器来计算命中数。






2.60/5 (2投票s)
基于 Apache 日志文件,报告来自本地主机和其他地方的访问次数的方法。
引言
有很多用于 Apache 日志文件的日志分析器,但总有一些特殊情况是它们都无法处理的,或者无法按照你希望的方式处理。
这是一个简单的 Perl 脚本,允许你根据访问者的 IP 地址来统计他们。
背景
在这种情况下,我需要统计来自 "localhost"(即 "127.0.0.1")的访问次数,以及来自其他地方的访问次数。我展示并解释了执行此操作的脚本。
使用代码
Apache 生成的日志文件有很多行,所有行都以类似的内容开头
127.0.0.1 - - [10/Apr/2007:10:39:11 +0300] ...
127.0.0.1 - - [10/Apr/2007:10:39:11 +0300] ...
139.12.0.2 - - [10/Apr/2007:10:40:54 +0300] ...
217.1.20.22 - - [10/Apr/2007:10:40:54 +0300] ...
首先是 IP 地址,然后是一个空格,一个破折号 (-),然后是更多的数据。
脚本看起来像这样
#!/usr/bin/perl
use strict;
use warnings;
my $file = shift or die "Usage: $0 FILE\n";
open my $fh, '<', $file or die "Could not open '$file': $!";
my $local = 0;
my $remote = 0;
while (my $line = <$fh>) {
my $length = index ($line, " ");
my $ip = substr($line, 0, $length);
if ($ip eq "127.0.0.1") {
$local++;
} else {
$remote++;
}
}
print "Local: $local Remote: $remote\n";
将其保存为 "analyzer.pl" 并以 "perl analyzer.pl" 的方式运行它。
让我们来看看它。
第一行被称为 shebang。 只有当你希望将脚本变成 Unix/Linux 可执行文件时才需要它。
use strict;
use warnings;
这些非常类似于其他语言中的编译器标志。 它们帮助你避免常见的编程错误。 我称它们为安全网。 如果没有它们,我不会编写任何 Perl 脚本。
my $file = shift or die "Usage: $0 FILE\n";
最好分成两部分来解释
my $file = shift
将从 @ARGV
(保存命令行参数的数组) 中获取第一个元素,并将其移到 $file
变量中,该变量刚刚使用 "my
" 关键字声明。
然后是 "or
" 逻辑运算符。
如果用户提供了文件名,则 "or
" 的左侧将计算为真值,并且脚本继续执行。如果用户没有提供命令行参数,则 "or
" 的右侧将启动,Perl 将停止执行并显示使用消息。
Usage: analyze.pl FILENAME
open my $fh, '<', $file or die "Could not open '$file': $!";
以上是一个类似的逻辑表达式。 左侧打开 $file
进行读取,并将文件句柄放入新的 $fh
变量中。 如果成功,open
返回 true,脚本继续执行。 如果失败,open
返回 false
,右侧启动。 Perl 显示错误消息并停止执行。
然后我们声明两个标量变量,并将 0 分配给它们中的每一个。 我们将它们用作计数器,用于计算以 "127.0.0.1" 开头的行数和其他行数。
while
循环逐行读取文件,并为每一行执行该块的内容。 当我们完成读取文件时,while
将停止。
while (my $line = <$fh>) {
}
index()
函数获取一个字符串和一个子字符串,并返回子字符串(第二个参数)在第一个字符串中的位置。 它使用基于 0 的索引,并且我们正在寻找一个空格。 结果数字将是当前行中 IP 地址的长度。
my $length = index ($line, " ");
substr()
获取一个字符串、一个索引(偏移量)和一个长度。 它返回位于特定位置的子字符串。 在我们的例子中,这恰好是当前行的 IP 地址。
my $ip = substr($line, 0, $length);
唯一剩下的事情是检查这是否是 "localhost" 并递增相应的计数器。
if ($ip eq "127.0.0.1") {
$local++;
} else {
$remote++;
}
循环完成后,我们打印结果
print "Local: $local Remote: $remote\n";
就这样。现在你可以使用这个脚本,甚至可以根据说明改进它。请参阅下一篇文章以获取关于所有访问的 完整源代码分析。