
| Current Path : /var/www/html/vendor/drush/drush/src/Drupal/Commands/core/ |
Linux ift1.ift-informatik.de 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64 |
| Current File : /var/www/html/vendor/drush/drush/src/Drupal/Commands/core/WatchdogCommands.php |
<?php
namespace Drush\Drupal\Commands\core;
use Consolidation\OutputFormatters\StructuredData\PropertyList;
use Consolidation\OutputFormatters\StructuredData\RowsOfFields;
use Drupal\Core\Database\Database;
use Drupal\Core\Logger\RfcLogLevel;
use Drupal\Core\Session\AnonymousUserSession;
use Drupal\user\Entity\User;
use Drush\Commands\DrushCommands;
use Drupal\Component\Utility\Unicode;
use Drupal\Component\Utility\Html;
use Drush\Drupal\DrupalUtil;
use Drush\Exceptions\UserAbortException;
use Symfony\Component\Console\Output\OutputInterface;
class WatchdogCommands extends DrushCommands
{
/**
* Show watchdog messages.
*
* @command watchdog:show
* @param $substring A substring to look search in error messages.
* @option count The number of messages to show.
* @option severity Restrict to messages of a given severity level (numeric or string).
* @option severity-min Restrict to messages of a given severity level and higher.
* @option type Restrict to messages of a given type.
* @option extended Return extended information about each message.
* @usage drush watchdog:show
* Show a listing of most recent 10 messages.
* @usage drush watchdog:show "cron run successful"
* Show a listing of most recent 10 messages containing the string <info>cron run successful</info>.
* @usage drush watchdog:show --count=46
* Show a listing of most recent 46 messages.
* @usage drush watchdog:show --severity=Notice
* Show a listing of most recent 10 messages with a severity of notice.
* @usage drush watchdog:show --severity-min=Warning
* Show a listing of most recent 10 messages with a severity of warning or higher.
* @usage drush watchdog:show --type=php
* Show a listing of most recent 10 messages of type php
* @aliases wd-show,ws,watchdog-show
* @validate-module-enabled dblog
* @field-labels
* wid: ID
* type: Type
* message: Message
* severity: Severity
* location: Location
* hostname: Hostname
* date: Date
* username: Username
* uid: Uid
* @default-fields wid,date,type,severity,message
* @filter-default-field message
* @return RowsOfFields
*/
public function show($substring = '', $options = ['format' => 'table', 'count' => 10, 'severity' => self::REQ, 'severity-min' => self::REQ, 'type' => self::REQ, 'extended' => false])
{
$where = $this->where($options['type'], $options['severity'], $substring, 'AND', $options['severity-min']);
$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.'));
return;
} 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.
* @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
*/
public function watchdogList($substring = '', $options = ['format' => 'table', 'count' => 10, 'extended' => false]): RowsOfFields
{
return $this->show($substring, $options);
}
/**
* Tail watchdog messages.
*
* @command watchdog:tail
* @param OutputInterface $output
* @param $substring A substring to look search in error messages.
* @option severity Restrict to messages of a given severity level (numeric or string).
* @option severity-min Restrict to messages of a given severity level and higher.
* @option type Restrict to messages of a given type.
* @option extended Return extended information about each message.
* @usage drush watchdog:tail
* Continuously tail watchdog messages.
* @usage drush watchdog:tail "cron run successful"
* Continuously tail watchdog messages, filtering on the string <info>cron run successful</info>.
* @usage drush watchdog:tail --severity=Notice
* Continuously tail watchdog messages, filtering severity of notice.
* @usage drush watchdog:tail --severity-min=Warning
* Continuously tail watchdog messages, filtering for a severity of warning or higher.
* @usage drush watchdog:tail --type=php
* Continuously tail watchdog messages, filtering on type equals php.
* @aliases wd-tail,wt,watchdog-tail
* @validate-module-enabled dblog
* @version 10.6
*/
public function tail(OutputInterface $output, $substring = '', $options = ['severity' => self::REQ, 'severity-min' => self::REQ, 'type' => self::REQ, 'extended' => false]): void
{
$where = $this->where($options['type'], $options['severity'], $substring, 'AND', $options['severity-min']);
if (empty($where['where'])) {
$where = [
'where' => 'wid > :wid',
'args' => [],
];
} else {
$where['where'] .= " AND wid > :wid";
}
$last_seen_wid = 0;
$iteration = 1;
while (true) {
$iteration++;
$where['args'][':wid'] = $last_seen_wid;
$query = Database::getConnection()->select('watchdog', 'w')
->fields('w')
->orderBy('wid', 'DESC');
if ($last_seen_wid === 0) {
$query->range(0, 10);
}
$query->where($where['where'], $where['args']);
$rsc = $query->execute();
while ($result = $rsc->fetchObject()) {
if ($result->wid > $last_seen_wid) {
$last_seen_wid = $result->wid;
}
$row = $this->formatResult($result, $options['extended']);
$msg = "{$row->wid}\t{$row->date}\t{$row->type}\t{$row->severity}\t{$row->message}";
$output->writeln($msg);
}
sleep(2);
}
}
/**
* @hook interact watchdog-list
* @throws UserAbortException
*/
public function interactList($input, $output): void
{
$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
*/
public function delete($substring = '', $options = ['severity' => self::REQ, 'type' => self::REQ]): void
{
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.'));
} elseif (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
*/
public function showOne($id, $options = ['format' => 'yaml']): PropertyList
{
$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, true));
}
/**
* 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.
* @param $severity_min
* Int or String for the minimum severity to return.
* @return
* An array with structure ('where' => string, 'args' => array())
*/
protected function where($type = null, $severity = null, $filter = null, $criteria = 'AND', $severity_min = null): array
{
$args = [];
$conditions = [];
if ($type) {
$types = $this->messageTypes();
if (!in_array($type, $types)) {
$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 (!empty($severity) && !empty($severity_min)) {
$msg = "--severity=!severity --severity-min=!severity_min\nYou may provide a value for one of these parameters but not both.";
throw new \Exception(dt($msg, ['!severity' => $severity, '!severity_min' => $severity_min]));
}
// From here we know that only one of --severity or --severity-min might
// have a value but not both of them.
if (!empty($severity) || !empty($severity_min)) {
if (empty($severity)) {
$severity = $severity_min;
$operator = '<=';
} else {
$operator = '=';
}
$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 {$operator} :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 = date('d/M H:i', $result->timestamp);
unset($result->timestamp);
// Username.
$result->username = (new AnonymousUserSession())->getAccountName() ?: dt('Anonymous');
$account = User::load($result->uid);
if ($account && !$account->isAnonymous()) {
$result->username = $account->getAccountName();
}
// 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);
}
$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();
}
}