【问题标题】:How to get each error from error log file?如何从错误日志文件中获取每个错误?
【发布时间】:2018-07-08 09:23:33
【问题描述】:

我想获取日志错误文件中的每个错误。

所以如果文件包含:

[08-Jul-2018 08:12:04 UTC] PHP Fatal error:  Call to undefined method DateTime::fomat() in C:\xampp\htdocs\wordpress\wp-content\themes\theme\index.php on line 44

[08-Jul-2018 08:22:22 UTC] PHP Fatal error:  Uncaught exception 'PDOException' with message 'SQLSTATE[42S02]: Base table or view not found: 1146 Table 'database.table' doesn't exist' in C:\xampp\htdocs\wordpress\wp-content\themes\theme\index.php:37
Stack trace:
#0 C:\xampp\htdocs\wordpress\wp-content\themes\news_theme\index.php(37): 
PDOStatement->execute()
#1 C:\xampp\htdocs\wordpress\wp-includes\template-loader.php(74): 
include('C:\\xampp\\htdocs...')
#2 C:\xampp\htdocs\wordpress\wp-blog-header.php(19): 
require_once('C:\\xampp\\htdocs...')
#3 C:\xampp\htdocs\wordpress\index.php(17): require('C:\\xampp\\htdocs...')
#4 {main}
thrown in C:\xampp\htdocs\wordpress\wp-content\themes\theme\index.php on line 37

这是两个错误,但其中一个很长,需要多于一行。

我想将它们的每个错误都放在一个变量中。

我试过了:

$contents  = file(get_template_directory().'/errors.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($contents as $key => $content) {
    echo $key . $content . '<br>';
}

但这会获取每一行,所以第二行将存储在几个变量中,我想在一个变量中获取每个错误。

这可能吗?

【问题讨论】:

  • Warning: preg_split() expects parameter 2 to be string, array given, $contents 是一个包含文本行的数组
  • 我把它改成$contents = file_get_contents();然后$contents = preg_split();,但是它返回一个数组,其中一个值是整个文本
  • 好吧,可能我放错了^,试试'~\s+(?=^\[\d{2}-\w{3}-\d{4} \d+(?::\d{2}){2} \w{3}])~m'。您仍然可以逐行读取文件,检查是否有行 preg_match('~^\[\d{2}-\w{3}-\d{4} \d+(?::\d{2}){2} \w{3}]~', $line) 并将这些行添加到临时变量中,然后再找到与该模式或字符串结尾匹配的另一行。
  • 我尝试了preg_split('/\s+(?=^\[\d{2}-\w{3}-\d{4} \d+(?::\d{2}){2} \w{3}])/m', $contents);,它成功了,它到底会匹配什么?

标签: php regex wordpress error-handling filesystems


【解决方案1】:

使用file_get_contents将文件作为单个字符串读入,然后使用

$splits = preg_split('/\s+(?=^\[\d{2}-\w{3}-\d{4} \d+(?::\d{2}){2} \w{3}])/m', $contents);

模式匹配

  • \s+ - 1+ 个空格后跟...
  • (?=^\[\d{2}-\w{3}-\d{4} \d+(?::\d{2}){2} \w{3}]) - 一个积极的前瞻,紧挨当前位置的右侧,需要:
    • ^ - 行首(由于 m 修饰符)
    • \[ - 一个 [ 字符
    • \d{2}-\w{3}-\d{4} - 2 位,-,3 个字字符,-,4 位
    • - 一个空格
    • \d+ - 1 位以上
    • (?::\d{2}){2} - 出现 2 次 : 和 2 位数字(与 :\d{2}:\d{2} 相同)
    • - 一个空格
    • \w{3} - 3 个单词字符(字母、数字或 _
    • ] - ] 字符。

请参阅regex demo

【讨论】:

  • 所以它匹配[08-Jul-2018 08:12:04 UTC][08-Jul-2018 08:22:22 UTC],或者其他部分?
  • @Dan 差不多,它匹配 1+ 个空格,后面跟 [08-Jul-2018 08:12:04 UTC] only 之类的值在行的开头。由于日期时间模式在前瞻中,因此它们不会被消耗,因此会保留在输出中。
  • 很好,因为它不匹配特定的单词或字符
  • @Dan 正确,但如果你想让它“更安全”,你总是可以让它更具体。例如。 \s+(?=^\[\d{2}-(?:Jan|Feb|Ma[ry]|Apr|Ju[nl]|Aug|Sept?|Oct|Nov|Dec)-\d{4} \d+(?::\d{2}){2} [A-Z]{3}]).
  • @Dan 不可能,全部搞定然后用array_slice
【解决方案2】:

您的代码只是逐一打印每个输入行及其编号。

要将输入分成块,对于每个错误,您可以采取 以下方法:

  • 整个文件读入一个变量中。
  • 执行例如preg_match_all 就可以了。

使用的正则表达式应该匹配:

  • ^\[[^\]]+\] - 初始部分 - 括号之间的日期/时间,来自 行首(由于m 选项)。
  • [^\n]+ - \n 以外的一系列字符 - 此行的其余部分。

现在剩下的 - 可选的非捕获组 - (?:...)?,包含:

  • \nStack trace: - “更长”消息的开始部分,再次 从行首开始。
  • .+ - “中间部分” - 堆栈跟踪的实际内容。 由于s 选项,它也匹配\n 字符,结束这些“中间”行。
  • \nthrown - 要匹配的最后一行 - 从行首抛出
  • .+?$ - 任意数量的任意字符,直到此(最后)行的末尾。

匹配多行和每行的开始/结束, 使用ms 正则表达式选项。

下面有一个示例程序,匹配一个常量文本,而不是 输入文件:

<?php
$text = <<<'EOD'
[08-Jul-2018 08:12:04 UTC] PHP Fatal error: on line 44
[08-Jul-2018 08:22:22 UTC] PHP Fatal error: in ...:37
Stack trace:
#0 C:\xampp\htdocs\wordpress\wp-content\themes\news_theme\index.php(37): 
PDOStatement->execute()
#1 C:\xampp\htdocs\wordpress\wp-includes\template-loader.php(74): 
include('C:\\xampp\\htdocs...')
thrown in ... on line 37
[08-Jul-2018 08:12:45 UTC] PHP Fatal error: on line 155
EOD;

$pattern = '/^\[[^\]]+\]\D+\d+\n(?:Stack trace:.+\nthrown.+?$)?/ms';
if (preg_match_all($pattern, $text, $matches))
    print_r($matches[0]);
?>

根据需要只打印 3 个匹配项。

编辑

如果您还有其他错误情况,请尝试另一个正则表达式:

^\[[^\]]+\][^\n]+(?:\n[^\[\n][^\n]+)*

这一次,只有m 选项。它匹配:

  • ^\[[^\]]+\][^\n]+ - “起始”行 - [...]...
  • (?:\n[^\[\n][^\n]+)* - 任意数量(包括 0)的非空跟随 行,不是从 [ 开始的。

有关最后一个正则表达式的工作示例,请参阅 https://regex101.com/r/0IUkc0/1

【讨论】:

  • 谢谢,但是文件会包含各种错误,不仅仅是这两个,哪三个匹配?只有 2 个错误。
  • 我使用 rextester.com/l/php_online_compiler 测试了我的代码,它运行时没有任何错误。如果您的日志文件包含其他错误,也许您应该扩展我的正则表达式(非捕获组),以匹配其他替代方案。也许它应该是任何不以[开头的行。
  • 我假设每个“发现”都应该从行首的[...](日期/时间)开始,然后是任意数量的“后续”非空行,从其他字符(不是[)。你想只匹配错误,跳过其他类的消息吗?
  • 你没有使用 m 选项。我想,这就是原因。请注意我在“编辑”之后的评论: ... 带有 m 选项。
  • 如果你有正则表达式的问题,一个很好的测试工具是 regex101.com
猜你喜欢
  • 2017-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-13
  • 1970-01-01
  • 2015-03-05
  • 1970-01-01
  • 2011-01-05
相关资源
最近更新 更多