* @since 2.0 */ class LogTarget extends Target { /** * @var Module */ public $module; public $tag; /** * @param \yii\debug\Module $module * @param array $config */ public function __construct($module, $config = []) { parent::__construct($config); $this->module = $module; $this->tag = uniqid(); } /** * Exports log messages to a specific destination. * Child classes must implement this method. */ public function export() { $path = $this->module->dataPath; if (!is_dir($path)) { mkdir($path); } $indexFile = "$path/index.data"; if (!is_file($indexFile)) { $manifest = []; } else { $manifest = unserialize(file_get_contents($indexFile)); } $request = Yii::$app->getRequest(); $response = Yii::$app->getResponse(); $manifest[$this->tag] = $summary = [ 'tag' => $this->tag, 'url' => $request->getAbsoluteUrl(), 'ajax' => $request->getIsAjax(), 'method' => $request->getMethod(), 'ip' => $request->getUserIP(), 'time' => time(), 'statusCode' => $response->statusCode, 'sqlCount' => $this->getSqlTotalCount(), ]; $this->gc($manifest); $dataFile = "$path/{$this->tag}.data"; $data = []; foreach ($this->module->panels as $id => $panel) { $data[$id] = $panel->save(); } $data['summary'] = $summary; file_put_contents($dataFile, serialize($data)); file_put_contents($indexFile, serialize($manifest)); } /** * Processes the given log messages. * This method will filter the given messages with [[levels]] and [[categories]]. * And if requested, it will also export the filtering result to specific medium (e.g. email). * @param array $messages log messages to be processed. See [[Logger::messages]] for the structure * of each message. * @param boolean $final whether this method is called at the end of the current application */ public function collect($messages, $final) { $this->messages = array_merge($this->messages, $messages); if ($final) { $this->export($this->messages); } } protected function gc(&$manifest) { if (count($manifest) > $this->module->historySize + 10) { $n = count($manifest) - $this->module->historySize; foreach (array_keys($manifest) as $tag) { $file = $this->module->dataPath . "/$tag.data"; @unlink($file); unset($manifest[$tag]); if (--$n <= 0) { break; } } } } /** * Returns total sql count executed in current request. If database panel is not configured * returns 0. * @return integer */ protected function getSqlTotalCount() { if (!isset($this->module->panels['db'])) { return 0; } $profileLogs = $this->module->panels['db']->save(); # / 2 because messages are in couple (begin/end) return count($profileLogs['messages']) / 2; } }