CakePHP 3.x: 记录为序列化数组
CakePHP 3.x: log as serialized array
我正在为 CakePHP 编写自己的解析器日志。
我只需要一件事:那不是写入日志"message"(作为字符串),而是包含各种日志信息(日期、类型、行、堆栈跟踪等)的序列化数组。
但是我不明白method/class我应该重写什么,虽然我已经查阅了API。你能帮帮我吗?
编辑:
现在我做了相反的事情:我阅读了日志(已经写好了),然后用正则表达式将它们转换成一个数组。
我的代码:
$logs = array_map(function($log) {
preg_match('/^'.
'([\d\-]+\s[\d:]+)\s(Error: Fatal Error|Error|Notice: Notice|Warning: Warning)(\s\(\d+\))?:\s([^\n]+)\n'.
'(Exception Attributes:\s((.(?!Request|Referer|Stack|Trace))+)\n)?'.
'(Request URL:\s([^\n]+)\n)?'.
'(Referer URL:\s([^\n]+)\n)?'.
'(Stack Trace:\n(.+))?'.
'(Trace:\n(.+))?(.+)?'.
'/si', $log, $matches);
switch($matches[2]) {
case 'Error: Fatal Error':
$type = 'fatal';
break;
case 'Error':
$type = 'error';
break;
case 'Notice: Notice':
$type = 'notice';
break;
case 'Warning: Warning':
$type = 'warning';
break;
default:
$type = 'unknown';
break;
}
return (object) af([
'datetime' => \Cake\I18n\FrozenTime::parse($matches[1]),
'type' => $type,
'error' => $matches[4],
'attributes' => empty($matches[6]) ? NULL : $matches[6],
'url' => empty($matches[9]) ? NULL : $matches[9],
'referer' => empty($matches[11]) ? NULL : $matches[11],
'stack_trace' => empty($matches[13]) ? (empty($matches[16]) ? NULL : $matches[16]) : $matches[13],
'trace' => empty($matches[15]) ? NULL : $matches[15]
]);
}, af(preg_split('/[\r\n]{2,}/', $logs)));
现在我做相反的事情:我阅读日志(已经写好)并使用正则表达式将它们转换为数组。
问题是这太贵了。最好做相反的事情:将日志作为序列化数组直接写入日志。
我想你想做的是自己写 LogAdapter。
您只需按照文档中所述创建一个 class ArrayLog(扩展 BaseLog)并配置 cakePHP 以使用它。在日志函数中,您可以将 $level、$message 和 $context 等信息作为数组附加到文件中。这将生成一个包含多个数组的日志文件,然后可以拆分这些数组。
话虽这么说,我还是建议登录到数据库并读出而不是解析。
好的,就是这样!
(请注意,此代码绝对是实验性的,我尚未对其进行适当的测试)
我想做的一件有趣的事情:对于每个日志,写入序列化文件并同时写入计划文件。
这使我可以将日志作为纯文本文件读取,也可以使用序列化文件对其进行操作。
use Cake\Log\Engine\FileLog;
class SerializedLog extends FileLog {
protected function _getLogAsArray($level, $message) {
$serialized['level'] = $level;
$serialized['datetime'] = date('Y-m-d H:i:s');
//Sets exception type and message
if(preg_match('/^(\[([^\]]+)\]\s)?(.+)/', $message, $matches)) {
if(!empty($matches[2]))
$serialized['exception'] = $matches[2];
$serialized['message'] = $matches[3];
}
//Sets the exception attributes
if(preg_match('/Exception Attributes:\s((.(?!Request URL|Referer URL|Stack Trace|Trace))+)/is', $message, $matches)) {
$serialized['attributes'] = $matches[1];
}
//Sets the request URL
if(preg_match('/^Request URL:\s(.+)$/mi', $message, $matches)) {
$serialized['request'] = $matches[1];
}
//Sets the referer URL
if(preg_match('/^Referer URL:\s(.+)$/mi', $message, $matches)) {
$serialized['referer'] = $matches[1];
}
//Sets the trace
if(preg_match('/(Stack )?Trace:\n(.+)$/is', $message, $matches)) {
$serialized['trace'] = $matches[2];
}
$serialized['full'] = date('Y-m-d H:i:s').' '.ucfirst($level).': '.$message;
return (object) $serialized;
}
public function log($level, $message, array $context = []) {
$message = $this->_format(trim($message), $context);
$filename = $this->_getFilename($level);
if (!empty($this->_size)) {
$this->_rotateFile($filename);
}
$pathname = $this->_path . $filename;
$mask = $this->_config['mask'];
//Gets the content of the existing logs and unserializes
$logs = @unserialize(@file_get_contents($pathname));
if(empty($logs) || !is_array($logs))
$logs = [];
//Adds the current log
$logs[] = $this->_getLogAsArray($level, $message);
//Serializes logs
$output = serialize($logs);
if (empty($mask)) {
return file_put_contents($pathname, $output);
}
$exists = file_exists($pathname);
$result = file_put_contents($pathname, $output);
static $selfError = false;
if (!$selfError && !$exists && !chmod($pathname, (int)$mask)) {
$selfError = true;
trigger_error(vsprintf(
'Could not apply permission mask "%s" on log file "%s"',
[$mask, $pathname]
), E_USER_WARNING);
$selfError = false;
}
return $result;
}
}
我正在为 CakePHP 编写自己的解析器日志。
我只需要一件事:那不是写入日志"message"(作为字符串),而是包含各种日志信息(日期、类型、行、堆栈跟踪等)的序列化数组。
但是我不明白method/class我应该重写什么,虽然我已经查阅了API。你能帮帮我吗?
编辑:
现在我做了相反的事情:我阅读了日志(已经写好了),然后用正则表达式将它们转换成一个数组。
我的代码:
$logs = array_map(function($log) {
preg_match('/^'.
'([\d\-]+\s[\d:]+)\s(Error: Fatal Error|Error|Notice: Notice|Warning: Warning)(\s\(\d+\))?:\s([^\n]+)\n'.
'(Exception Attributes:\s((.(?!Request|Referer|Stack|Trace))+)\n)?'.
'(Request URL:\s([^\n]+)\n)?'.
'(Referer URL:\s([^\n]+)\n)?'.
'(Stack Trace:\n(.+))?'.
'(Trace:\n(.+))?(.+)?'.
'/si', $log, $matches);
switch($matches[2]) {
case 'Error: Fatal Error':
$type = 'fatal';
break;
case 'Error':
$type = 'error';
break;
case 'Notice: Notice':
$type = 'notice';
break;
case 'Warning: Warning':
$type = 'warning';
break;
default:
$type = 'unknown';
break;
}
return (object) af([
'datetime' => \Cake\I18n\FrozenTime::parse($matches[1]),
'type' => $type,
'error' => $matches[4],
'attributes' => empty($matches[6]) ? NULL : $matches[6],
'url' => empty($matches[9]) ? NULL : $matches[9],
'referer' => empty($matches[11]) ? NULL : $matches[11],
'stack_trace' => empty($matches[13]) ? (empty($matches[16]) ? NULL : $matches[16]) : $matches[13],
'trace' => empty($matches[15]) ? NULL : $matches[15]
]);
}, af(preg_split('/[\r\n]{2,}/', $logs)));
现在我做相反的事情:我阅读日志(已经写好)并使用正则表达式将它们转换为数组。
问题是这太贵了。最好做相反的事情:将日志作为序列化数组直接写入日志。
我想你想做的是自己写 LogAdapter。 您只需按照文档中所述创建一个 class ArrayLog(扩展 BaseLog)并配置 cakePHP 以使用它。在日志函数中,您可以将 $level、$message 和 $context 等信息作为数组附加到文件中。这将生成一个包含多个数组的日志文件,然后可以拆分这些数组。
话虽这么说,我还是建议登录到数据库并读出而不是解析。
好的,就是这样!
(请注意,此代码绝对是实验性的,我尚未对其进行适当的测试)
我想做的一件有趣的事情:对于每个日志,写入序列化文件并同时写入计划文件。 这使我可以将日志作为纯文本文件读取,也可以使用序列化文件对其进行操作。
use Cake\Log\Engine\FileLog;
class SerializedLog extends FileLog {
protected function _getLogAsArray($level, $message) {
$serialized['level'] = $level;
$serialized['datetime'] = date('Y-m-d H:i:s');
//Sets exception type and message
if(preg_match('/^(\[([^\]]+)\]\s)?(.+)/', $message, $matches)) {
if(!empty($matches[2]))
$serialized['exception'] = $matches[2];
$serialized['message'] = $matches[3];
}
//Sets the exception attributes
if(preg_match('/Exception Attributes:\s((.(?!Request URL|Referer URL|Stack Trace|Trace))+)/is', $message, $matches)) {
$serialized['attributes'] = $matches[1];
}
//Sets the request URL
if(preg_match('/^Request URL:\s(.+)$/mi', $message, $matches)) {
$serialized['request'] = $matches[1];
}
//Sets the referer URL
if(preg_match('/^Referer URL:\s(.+)$/mi', $message, $matches)) {
$serialized['referer'] = $matches[1];
}
//Sets the trace
if(preg_match('/(Stack )?Trace:\n(.+)$/is', $message, $matches)) {
$serialized['trace'] = $matches[2];
}
$serialized['full'] = date('Y-m-d H:i:s').' '.ucfirst($level).': '.$message;
return (object) $serialized;
}
public function log($level, $message, array $context = []) {
$message = $this->_format(trim($message), $context);
$filename = $this->_getFilename($level);
if (!empty($this->_size)) {
$this->_rotateFile($filename);
}
$pathname = $this->_path . $filename;
$mask = $this->_config['mask'];
//Gets the content of the existing logs and unserializes
$logs = @unserialize(@file_get_contents($pathname));
if(empty($logs) || !is_array($logs))
$logs = [];
//Adds the current log
$logs[] = $this->_getLogAsArray($level, $message);
//Serializes logs
$output = serialize($logs);
if (empty($mask)) {
return file_put_contents($pathname, $output);
}
$exists = file_exists($pathname);
$result = file_put_contents($pathname, $output);
static $selfError = false;
if (!$selfError && !$exists && !chmod($pathname, (int)$mask)) {
$selfError = true;
trigger_error(vsprintf(
'Could not apply permission mask "%s" on log file "%s"',
[$mask, $pathname]
), E_USER_WARNING);
$selfError = false;
}
return $result;
}
}