'table', 'count' => 10, 'severity' => self::REQ, 'type' => self::REQ, 'extended' => false]) { $where = $this->where($options['type'], $options['severity'], $substring); $query = Database::getConnection()->select('watchdog', 'w') ->range(0, $options['count']) ->fields('w') ->orderBy('wid', 'DESC'); if (!empty($where['where'])) { $query->where($where['where'], $where['args']); } $rsc = $query->execute(); while ($result = $rsc->fetchObject()) { $row = $this->formatResult($result, $options['extended']); $table[$row->wid] = (array)$row; } if (empty($table)) { $this->logger()->notice(dt('No log messages available.')); } else { return new RowsOfFields($table); } } /** * Interactively filter the watchdog message listing. * * @command watchdog:list * @param $substring A substring to look search in error messages. * @option count The number of messages to show. Defaults to 10. * @option extended Return extended information about each message. * @option severity Restrict to messages of a given severity level. * @option type Restrict to messages of a given type. * @usage drush watchdog-list * Prompt for message type or severity, then run watchdog-show. * @aliases wd-list,watchdog-list * @hidden-options type,severity * @validate-module-enabled dblog * @field-labels * wid: ID * type: Type * message: Message * severity: Severity * location: Location * hostname: Hostname * date: Date * username: Username * @default-fields wid,date,type,severity,message * @return \Consolidation\OutputFormatters\StructuredData\RowsOfFields */ public function watchdogList($substring = '', $options = ['format' => 'table', 'count' => 10, 'extended' => false]) { return $this->show($substring, $options); } /** * @hook interact watchdog-list * @throws \Drush\Exceptions\UserAbortException */ public function interactList($input, $output) { $choices['-- types --'] = dt('== message types =='); $types = $this->messageTypes(); foreach ($types as $key => $type) { $choices[$key] = $type; } $choices['-- levels --'] = dt('== severity levels =='); $severities = RfcLogLevel::getLevels(); foreach ($severities as $key => $value) { $choices[$key] = $value; } $option = $this->io()->choice(dt('Select a message type or severity level'), $choices); if (isset($types[$option])) { $input->setOption('type', $types[$option]); } else { $input->setOption('severity', $option); } } /** * Delete watchdog log records. * * @command watchdog:delete * @param $substring Delete all log records with this text in the messages. * @option severity Delete messages of a given severity level. * @option type Delete messages of a given type. * @usage drush watchdog:delete all * Delete all messages. * @usage drush watchdog:delete 64 * Delete messages with id 64. * @usage drush watchdog:delete "cron run succesful" * Delete messages containing the string "cron run succesful". * @usage drush watchdog:delete --severity=notice * Delete all messages with a severity of notice. * @usage drush watchdog:delete --type=cron * Delete all messages of type cron. * @aliases wd-del,wd-delete,wd,watchdog-delete * @validate-module-enabled dblog * @return void */ public function delete($substring = '', $options = ['severity' => self::REQ, 'type' => self::REQ]) { if ($substring == 'all') { $this->output()->writeln(dt('All watchdog messages will be deleted.')); if (!$this->io()->confirm(dt('Do you really want to continue?'))) { throw new UserAbortException(); } $ret = Database::getConnection()->truncate('watchdog')->execute(); $this->logger()->success(dt('All watchdog messages have been deleted.')); } else if (is_numeric($substring)) { $this->output()->writeln(dt('Watchdog message #!wid will be deleted.', ['!wid' => $substring])); if (!$this->io()->confirm(dt('Do you want to continue?'))) { throw new UserAbortException(); } $affected_rows = Database::getConnection()->delete('watchdog')->condition('wid', $substring)->execute(); if ($affected_rows == 1) { $this->logger()->success(dt('Watchdog message #!wid has been deleted.', ['!wid' => $substring])); } else { throw new \Exception(dt('Watchdog message #!wid does not exist.', ['!wid' => $substring])); } } else { if ((empty($substring))&&(!isset($options['type']))&&(!isset($options['severity']))) { throw new \Exception(dt('No options provided.')); } $where = $this->where($options['type'], $options['severity'], $substring, 'OR'); $this->output()->writeln(dt('All messages with !where will be deleted.', ['!where' => preg_replace("/message LIKE %$substring%/", "message body containing '$substring'", strtr($where['where'], $where['args']))])); if (!$this->io()->confirm(dt('Do you want to continue?'))) { throw new UserAbortException(); } $affected_rows = Database::getConnection()->delete('watchdog') ->where($where['where'], $where['args']) ->execute(); $this->logger()->success(dt('!affected_rows watchdog messages have been deleted.', ['!affected_rows' => $affected_rows])); } } /** * Show one log record by ID. * * @command watchdog:show-one * @param $id Watchdog Id * @aliases wd-one,watchdog-show-one * @validate-module-enabled dblog * * @return \Consolidation\OutputFormatters\StructuredData\PropertyList */ public function showOne($id, $options = ['format' => 'yaml']) { $rsc = Database::getConnection()->select('watchdog', 'w') ->fields('w') ->condition('wid', (int)$id) ->range(0, 1) ->execute(); $result = $rsc->fetchObject(); if (!$result) { throw new \Exception(dt('Watchdog message #!wid not found.', ['!wid' => $id])); } return new PropertyList($this->formatResult($result)); } /** * Build a WHERE snippet based on given parameters. * * @param $type * String. Valid watchdog type. * @param $severity * Int or String for a valid watchdog severity message. * @param $filter * String. Value to filter watchdog messages by. * @param $criteria * ('AND', 'OR'). Criteria for the WHERE snippet. * @return * An array with structure ('where' => string, 'args' => array()) */ protected function where($type = null, $severity = null, $filter = null, $criteria = 'AND') { $args = []; $conditions = []; if ($type) { $types = $this->messageTypes(); if (array_search($type, $types) === false) { $msg = "Unrecognized message type: !type.\nRecognized types are: !types."; throw new \Exception(dt($msg, ['!type' => $type, '!types' => implode(', ', $types)])); } $conditions[] = "type = :type"; $args[':type'] = $type; } if (isset($severity)) { $severities = RfcLogLevel::getLevels(); if (isset($severities[$severity])) { $level = $severity; } elseif (($key = array_search($severity, $severities)) !== false) { $level = $key; } else { $level = false; } if ($level === false) { foreach ($severities as $key => $value) { $levels[] = "$value($key)"; } $msg = "Unknown severity level: !severity.\nValid severity levels are: !levels."; throw new \Exception(dt($msg, ['!severity' => $severity, '!levels' => implode(', ', $levels)])); } $conditions[] = 'severity = :severity'; $args[':severity'] = $level; } if ($filter) { $conditions[] = "message LIKE :filter"; $args[':filter'] = '%'.$filter.'%'; } $where = implode(" $criteria ", $conditions); return ['where' => $where, 'args' => $args]; } /** * Format a watchdog database row. * * @param $result * Array. A database result object. * @param $extended * Boolean. Return extended message details. * @return * Array. The result object with some attributes themed. */ protected function formatResult($result, $extended = false) { // Severity. $severities = RfcLogLevel::getLevels(); $result->severity = trim(DrupalUtil::drushRender($severities[$result->severity])); // Date. $result->date = format_date($result->timestamp, 'custom', 'd/M H:i'); unset($result->timestamp); // Message. $variables = $result->variables; if (is_string($variables)) { $variables = unserialize($variables); } if (is_array($variables)) { $result->message = strtr($result->message, $variables); } unset($result->variables); $message_length = 188; // Print all the data available if ($extended) { // Possible empty values. if (empty($result->link)) { unset($result->link); } if (empty($result->referer)) { unset($result->referer); } // Username. if ($account = user_load($result->uid)) { $result->username = $account->name; } else { $result->username = dt('Anonymous'); } unset($result->uid); $message_length = PHP_INT_MAX; } $result->message = Unicode::truncate(strip_tags(Html::decodeEntities($result->message)), $message_length, false, false); return $result; } /** * Helper function to obtain the message types based on drupal version. * * @return * Array of watchdog message types. */ public static function messageTypes() { return _dblog_get_message_types(); } }