我正在尝试使用PHP解析.log文件。我的程序始终以“ killed”消息结尾。我尝试在具有相同输入.log文件的两个不同服务器上运行我的PHP程序。
最终,我需要计算.log文件中某个模式的实例。该.log文件是一个文本文件,每行具有各种文本。每行都有一个连字符,用作字段分隔符。给定行上的破折号“-”右边的任何文本都可以打折,而不考虑。
我有一个名为“调用者”的递归函数。我尝试重新编写代码以不使用递归。我对这种方法有不同的疑问。
我尝试将输出保存到变量或新文件中。两种方法都没有给我带来明显的优势。我认为输出(根据我的逻辑节省模式)不会导致内存问题。
我在代码中有一个嵌套循环。对于.log文件的每一行,我正在从左到右检查每个字符以找到破折号“-”。
每次运行PHP程序时,dmesg
命令都会显示如下一行:
UB 999的内存不足:OOM杀死进程950(php)的得分为0 ...
如何重新编写该代码,使其不以“被杀死”消息结尾?
(我的代码还没有计算出模式。我还没有准备好完成它。我只想进入中间步骤,它不以“ killed”一词结尾。)
这是我的代码:
<?php
$filea = "good.log";
$newf = fopen("new.txt", "w");
$file = fopen($filea, "r");
$charnum = 0;
$numlines = 0;
$temp = fopen($filea, "r");
while(!feof($temp)){
$line = fgets($temp);
$numlines++;
}
fclose($temp);
function caller($newf, $fileline, $charnum){
if ($fileline[$charnum] == '-') {
$x = $charnum;
$stringx = "";
for ($h = 0; $h < $x; $h++){
$stringx = $stringx.$fileline[$h];
}
fwrite($newf, $stringx);
fwrite($newf, "\n");
echo $stringx;
}
else {
$charnum = $charnum + 1;
caller($newf, $fileline, $charnum);
}
}
for ($k = 0; $k < $numlines; $k = $k++) {
$fileline = fgets($file);
$charnum = 0;
caller($newf, $fileline, $charnum);
}
fclose($newf);
fclose($file);
?>
答案 0 :(得分:1)
大概您的一条日志行不包含"-"
,因此您的函数可以无限递归。
删除递归并修复错误将给出:
function caller($newf, $fileline, $charnum){
$len = strlen($fileline);
for ( $i = $charnum; $i < $len; $i++ )
{
if ($fileline[$i] == '-') {
$x = $i;
$stringx = "";
for ($h = 0; $h < $x; $h++){
$stringx = $stringx.$fileline[$h];
}
fwrite($newf, $stringx);
fwrite($newf, "\n");
echo $stringx;
return;
}
}
}
一种更简单的方法是使用内置的PHP函数strpos
和substr
:
function caller($newf, $fileline){
$pos = strpos($fileline, "-");
if ( $pos !== FALSE )
{
$stringx = substr( $fileline, 0, $pos );
fwrite($newf, $stringx);
fwrite($newf, "\n");
echo $stringx;
}
}
顺便说一句,对行数进行计数的初始循环似乎没有必要?您可以这样做:
while(!feof($file)){
$fileline = fgets($file);
$charnum = 0;
caller($newf, $fileline, $charnum);
}
答案 1 :(得分:1)
因此,您的代码实际执行的操作是遍历日志文件并计算while循环中的行数。 (无需每次覆盖$line
。)
然后在您的for循环中,您一次向函数caller
传递一行,并指示charnum
0。
在函数中,您检查charnum
处的字符是否为-
,如果是,则继续执行操作。但是,如果不是-
,则继续下一个字符。
...您的问题是您通过递归调用caller
来做到这一点!因此,对于该行中的每个字符,您都会在调用堆栈上放置一个新的函数调用。不要这样最好在caller
函数中放置一个for循环,以使charnum
每次递增,并在最终找到break
时使用-
脱离for循环。那应该可以解决您的问题。
答案 2 :(得分:0)
如果您只是想将每行的部分放在短划线的左侧,则可以在一行中完成所有操作:
preg_match_all('/^([^-\n])\-/m', file_get_contents('good.log'), $matches);
此后,$matches[0]
将包含一个匹配的术语列表(包括破折号),而$matches[1]
将包含相同的列表而不包含破折号。例如,给定:
one two - three - four
no dash on this line
five - six
seven - eight
然后,$matches[1]
将是一个包含以下内容的数组:one two
,five
,seven