2016-03-03 2 views
-1

Я пишу собственный журнал парсера для CakePHP.CakePHP 3.x: журнал как сериализованный массив

Мне нужно только одно: это не сообщение «сообщение» журнала (как строка), а сериализованный массив с различными данными журнала (дата, тип, строка, трассировка стека и т. Д.).

Но я не понимаю, какой метод/класс я должен переписать, хотя я консультировался с API. Вы можете мне помочь?

EDIT:
На данный момент я делаю обратное: я читаю журналы (уже записаны) и преобразую их в массив с регулярным выражением.

Мой код:

$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

Я уже получил это, но где именно это данные? Вы говорите о журналах отладки/ошибок по умолчанию? т. е. должен ли каждый журнал быть сериализован? Или, может быть, просто ошибки? Возможно, вы используете собственный журнал, который должен быть затронут только один? Вам действительно нужно быть более конкретным. – 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 (extends BaseLog), как указано в документах, и настройте cakePHP для его использования. В функции журнала вы добавляете информацию как $ level, $ message и $ context в файл как массив. Это приведет к созданию файла журнала с несколькими массивами, которые затем могут быть разделены.

Это, как говорится, я предлагаю зайти в базу данных и прочитать ее вместо разбора.

+0

Спасибо @ DIDoS, я уже думал об этом. Проблема в том, что в этом случае аргумент '$ message' уже содержит окончательную строку, то есть различные конкатенированные данные. Конечно, всегда лучше делиться здесь (опять же с использованием регулярного выражения), но я хотел бы знать, можно ли работать вверх по течению. Возможно ли это, по вашему мнению? –

+0

Я считаю, что затронутый код - '_getMessage()', '_logError()' и '_logException()' методы из 'BaseErrorHandler'. Именно здесь для ошибок и исключений информация объединяется в строку. Как только они являются строками, они отправляются в журнал. Итак, возможно, нам нужно написать LogAdapter AND ErrorHandler. Считаете ли вы, что это правильно? –

Смежные вопросы