使用PHP从日志文件中提取数据

时间:2012-11-14 14:21:57

标签: php

我有一个服务器日志文件,我正在尝试创建一个PHP页面,该页面汇总了它存储的数据。日志中的每条记录都存储在一个新行中,格式为:

207.3.35.52 -- [2007-04-01 01:24:42] "GET index.php HTTP/1.0" 200 11411 "Mozilla/4.0"

//ip -- [timestamp] "GET url HTTP/1.0" status code bytes "user agent".

我正在尝试编写一个摘要,其中显示:请求总数,文章目录中的请求总数,消耗的总带宽以及最终404错误及其页面的数量。

PHP:

$handle = fopen('logfiles/april.log','r') or die ('File opening failed');
$requestsCount = 0;
    while (!feof($handle)) {
        $dd = fgets($handle);
        $requestsCount++;   
        $parts = explode('"', $dd);
        $statusCode = substr($parts[2], 0, 4);
        }
fclose($handle);

此代码打开文件并计算记录数量,分离并在记录中查找状态代码编号。当回显$ statusCode时,它确实显示了正确的信息,显示了日志中的所有状态代码。

接受两个争论以完成404错误的函数:

function requests404($l,$s) {
        $r =  substr_count($l,$s);
        return "Total 404 errors: ".$r."<br />";
}

回应结果:

echo requests404($statusCode, '404');

这个函数不起作用,它只返回0.使用PHP中的txt文件是我最弱的技能,我真的很感激一些帮助,因为我认为我可能会以完全错误的方式去做。感谢。

3 个答案:

答案 0 :(得分:2)

$handle = fopen('logfiles/april.log','r') or die ('File opening failed');
$requestsCount = 0;
$num404 = 0;

while (!feof($handle)) {
    $dd = fgets($handle);
    $requestsCount++;   
    $parts = explode('"', $dd);
    $statusCode = substr($parts[2], 0, 4);
    if (hasRequestType($statusCode, '404')) $num404++;
}

echo "Total 404 Requests: " . $num404 . "<br />";
fclose($handle);

function hasRequestType($l,$s) {
        return substr_count($l,$s) > 0;
}

答案 1 :(得分:2)

虽然我喜欢在许多方面使用PHP。解析日志并不是其中之一。

相反,我真的建议您考虑使用awk进行所有未来的日志解析工作。

这是一个简单的bash / awk脚本,它以一种易于阅读/易于理解的方式实现您的所有需求:

#!/bin/bash

awk '
BEGIN {
    total_requests = 0;
    total_requests_articles = 0;
    total_404s = 0;
    total_bandwidth = 0;
} {
    total_requests++;

    if ( $8 == "404" ) {
        total_404s++;
    }

    if ( $6 ~ /articles/ ) {
        total_requests_articles++;
    }

    total_bandwidth += $9
} END {
    printf "total requests: %i\n", total_requests
    printf "total requests for articles: %i\n", total_requests_articles
    printf "total 404s: %i\n", total_404s
    printf "total bandwidth used: %i\n", total_bandwidth
}' ${1}

将此文件用作演示:

207.3.35.52 -- [2007-04-01 01:24:42] "GET index.php HTTP/1.0" 200 11411 "Mozilla/4.0"
207.3.35.52 -- [2007-04-01 01:24:42] "GET index.php HTTP/1.0" 200 11411 "Mozilla/4.0"
207.3.35.52 -- [2007-04-01 01:24:42] "GET index.php HTTP/1.0" 200 11411 "Mozilla/4.0"
207.3.35.52 -- [2007-04-01 01:24:42] "GET articles/index.php HTTP/1.0" 404 11411 "Mozilla/4.0"
207.3.35.52 -- [2007-04-01 01:24:42] "GET articles/index.php HTTP/1.0" 200 11411 "Mozilla/4.0"
207.3.35.52 -- [2007-04-01 01:24:42] "GET index.php HTTP/1.0" 404 11411 "Mozilla/4.0"

以下是结果:

[root@hacklab5 tmp]# ./apache.bash apache.log
total requests: 6
total requests for articles: 2
total 404s: 2
total bandwidth used: 68466

只是说.. Awk太棒了。而且速度快。并为解析日志量身定制。现在,向大家学习一些好东西;)

干杯 -

答案 2 :(得分:0)

substr_count$statusCode中出现“404”的次数相加,$statusCode每次只有四个字节“200”(或“304”或“ 404“)一行日志。

因此,只要状态代码 404,您就会得到零,这是正确的。

您需要在每个输入行上调用requests404,并总计总和。

实际上使用数组可能会更好:

$totals = array(
    200 => 0,
    404 => 0,
    304 => 0,
);
$requestsCount = 0;
$bytesSent = 0;
$totalBytes = 0;
while (!feof($handle)) {
    $dd = fgets($handle);
    $requestsCount++;   
    $parts = explode('"', $dd);
    list($statusCode, $bytes) = explode(" ", $parts[2]);
    if (!isset($totals[$statusCode]))
       $totals[$statusCode] = 0;
    $totals[$statusCode]++;
    if (200 == $statusCode)
        $bytesSent += $bytes;
    $totalBytes += $bytes;
}
fclose($handle);


printf("We got $totals[404] 404 errors\n");

在循环结束时,$ totals将保持类似

的内容
{
    200 =>  12345,
    404 =>   1234,
    401 =>     22,
    304 =>   7890,
    ...
}