2016-03-03 60 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。你認爲是正確的嗎? –