2016-03-03 33 views
-1

我正在为CakePHP编写我自己的解析器日志。CakePHP 3.x:以序列化数组的形式登录

我只需要一件事:那就是不写一个日志“消息”(作为一个字符串),而是一个带有各种日志信息(日期,类型,行,堆栈跟踪等)的序列化数组。

但我不明白我应该重写什么方法/类,尽管我已经咨询了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))); 

现在我做相反的:我读日志(已书面),并用正则表达式我将其转化为一个数组。

问题是这是非常昂贵的。并且做相反的事情会更好:以序列化数组的形式直接写入日志。

+0

什么是“_parser log_”?这里的上下文是什么,在什么地方准确记录你想要以特定格式记录的内容? – ndm

+0

@ndm,看我的编辑。很简单:日志被写成一个字符串,其中包含各种信息(错误的类型,日期和时间,请求的引用者和URL,消息等)。 但我想成为一个具有该信息的序列化阵列 –

+0

我已经知道了,但数据究竟在哪里?你在谈论默认的调试/错误日志吗?即应该_every_日志被序列化?或者只是错误?你是否可能使用一个自定义记录器应该唯一受到影响?你真的需要更具体。 – ndm

回答

0

好吧,就是这样!

(注意,此代码绝对是实验性的,我还没有正确地测试它)

,我想做一件有趣的事:每个日志,同时写入序列化的文件,并在计划文件。 这使我可以将日志作为纯文本文件读取,也可以使用序列化文件进行操作。

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; 
    } 
} 
1

我想你想要做的是写你自己的LogAdapter。 您只需按照文档中所述创建类ArrayLog(扩展BaseLog)并配置cakePHP即可使用它。在日志函数中,你可以像数组一样将$ level,$ message和$ context等信息附加到文件中。这将导致一个包含多个数组的日志文件,然后可以分割。

这就是说,我会建议登录到数据库并阅读它而不是解析。

+0

谢谢@DIDoS,我已经想到了这一点。问题在于,在这种情况下,'$ message'参数已经包含最终的字符串,即各种连接的信息。 当然,最好在这里再分(再次使用正则表达式),但我想知道是否有可能在上游进行操作。你认为这可能吗? –

+0

我相信受影响的代码是来自'BaseErrorHandler'的'_getMessage()','_logError()'和'_logException()'方法。在这里,对于错误和异常,信息被连接成一个字符串。一旦他们是字符串,他们被发送到日志。 所以,也许我们需要编写一个LogAdapter和一个ErrorHandler。你认为是正确的吗? –