diff --git a/core/core.services.yml b/core/core.services.yml index 9dca742..06c024e 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -96,6 +96,9 @@ services: factory_class: Drupal\Core\Database\Database factory_method: getConnection arguments: [default] + logger.watchdog: + class: Drupal\Core\WatchdogLogger + arguments: ['@request'] keyvalue: class: Drupal\Core\KeyValueStore\KeyValueFactory arguments: ['@service_container'] @@ -161,7 +164,7 @@ services: arguments: ['@service_container'] controller_resolver: class: Drupal\Core\ControllerResolver - arguments: ['@service_container'] + arguments: ['@service_container', '@logger.watchdog'] http_kernel: class: Drupal\Core\HttpKernel arguments: ['@event_dispatcher', '@service_container', '@controller_resolver'] @@ -200,7 +203,7 @@ services: - [setFinalMatcher, ['@router.matcher.final_matcher']] router.generator: class: Drupal\Core\Routing\UrlGenerator - arguments: ['@router.route_provider', '@path.alias_manager.cached'] + arguments: ['@router.route_provider', '@path.alias_manager.cached', '@logger.watchdog'] router.dynamic: class: Symfony\Cmf\Component\Routing\DynamicRouter arguments: ['@router.request_context', '@router.matcher', '@router.generator'] @@ -419,3 +422,8 @@ services: token: class: Drupal\Core\Utility\Token arguments: ['@module_handler'] + watchdog_request_subscriber: + class: Drupal\Core\EventSubscriber\WatchdogRequestSubscriber + tags: + - { name: event_subscriber } + arguments: ['@logger.watchdog'] diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index 7dc75f5..14fa857 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -1398,7 +1398,7 @@ function drupal_serve_page_from_cache(stdClass $cache) { * Defines the critical hooks that force modules to always be loaded. */ function bootstrap_hooks() { - return array('watchdog'); + return array(); } /** @@ -1651,47 +1651,15 @@ function watchdog_exception($type, Exception $exception, $message = NULL, $varia * A link to associate with the message. * * @see watchdog_severity_levels() - * @see hook_watchdog() + * @see \Drupal\Core\WatchdogLogger::log() */ function watchdog($type, $message, array $variables = NULL, $severity = WATCHDOG_NOTICE, $link = NULL) { - global $user, $base_root; - - static $in_error_state = FALSE; - - // It is possible that the error handling will itself trigger an error. In that case, we could - // end up in an infinite loop. To avoid that, we implement a simple static semaphore. - if (!$in_error_state && function_exists('module_implements')) { - $in_error_state = TRUE; - - // The user object may not exist in all conditions, so 0 is substituted if needed. - $user_uid = isset($user->uid) ? $user->uid : 0; - - // Prepare the fields to be logged - $log_entry = array( - 'type' => $type, - 'message' => $message, - 'variables' => $variables, - 'severity' => $severity, - 'link' => $link, - 'user' => $user, - 'uid' => $user_uid, - 'request_uri' => $base_root . request_uri(), - 'referer' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '', - 'ip' => Drupal::request()->getClientIP(), - // Request time isn't accurate for long processes, use time() instead. - 'timestamp' => time(), - ); - - // Call the logging hooks to log/process the message - foreach (module_implements('watchdog') as $module) { - $function = $module . '_watchdog'; - $function($log_entry); - } - - // It is critical that the semaphore is only cleared here, in the parent - // watchdog() call (not outside the loop), to prevent recursive execution. - $in_error_state = FALSE; - } + $context = array( + 'type' => $type, + 'variables' => $variables, + 'link' => $link, + ); + Drupal::service('logger.watchdog')->log($severity, $message, $context); } /** diff --git a/core/lib/Drupal/Core/ControllerResolver.php b/core/lib/Drupal/Core/ControllerResolver.php index e442427..fa26da1 100644 --- a/core/lib/Drupal/Core/ControllerResolver.php +++ b/core/lib/Drupal/Core/ControllerResolver.php @@ -7,8 +7,8 @@ namespace Drupal\Core; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Controller\ControllerResolver as BaseControllerResolver; -use Symfony\Component\HttpKernel\Log\LoggerInterface; use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -41,7 +41,7 @@ class ControllerResolver extends BaseControllerResolver { * * @param Symfony\Component\DependencyInjection\ContainerInterface $container * A ContainerInterface instance. - * @param Symfony\Component\HttpKernel\Log\LoggerInterface $logger + * @param \Psr\Log\LoggerInterface $logger * (optional) A LoggerInterface instance. */ public function __construct(ContainerInterface $container, LoggerInterface $logger = NULL) { diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php index 2d85f6a..1387159 100644 --- a/core/lib/Drupal/Core/CoreBundle.php +++ b/core/lib/Drupal/Core/CoreBundle.php @@ -16,6 +16,7 @@ use Drupal\Core\DependencyInjection\Compiler\RegisterRouteEnhancersPass; use Drupal\Core\DependencyInjection\Compiler\RegisterParamConvertersPass; use Drupal\Core\DependencyInjection\Compiler\RegisterServicesForDestructionPass; +use Drupal\Core\DependencyInjection\Compiler\RegisterWatchdogLoggersPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Reference; @@ -60,6 +61,8 @@ public function build(ContainerBuilder $container) { // Add the compiler pass that will process the tagged services. $container->addCompilerPass(new RegisterPathProcessorsPass()); $container->addCompilerPass(new ListCacheBinsPass()); + // Add a compiler pass for registering logging services. + $container->addCompilerPass(new RegisterWatchdogLoggersPass()); } /** diff --git a/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterWatchdogLoggersPass.php b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterWatchdogLoggersPass.php new file mode 100644 index 0000000..cf5c449 --- /dev/null +++ b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterWatchdogLoggersPass.php @@ -0,0 +1,31 @@ +hasDefinition('logger.watchdog')) { + return; + } + + $definition = $container->getDefinition('logger.watchdog'); + + foreach ($container->findTaggedServiceIds('watchdog_logger') as $id => $attributes) { + $definition->addMethodCall('addLogger', array(new Reference($id))); + } + } + +} diff --git a/core/lib/Drupal/Core/EventSubscriber/WatchdogRequestSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/WatchdogRequestSubscriber.php new file mode 100644 index 0000000..66ebbcb --- /dev/null +++ b/core/lib/Drupal/Core/EventSubscriber/WatchdogRequestSubscriber.php @@ -0,0 +1,62 @@ +watchdogLogger = $watchdog_logger; + } + + /** + * Sets the request on the watchdog logger. + * + * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event + * The Event to process. + */ + public function setWatchdogLoggerRequest(GetResponseEvent $event) { + if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) { + $this->watchdogLogger->setRequest($event->getRequest()); + } + } + + /** + * Registers the methods in this class that should be listeners. + * + * @return array + * An array of event listener definitions. + */ + static function getSubscribedEvents() { + $events[KernelEvents::REQUEST][] = array('setWatchdogLoggerRequest', 350); + + return $events; + } + +} diff --git a/core/lib/Drupal/Core/Routing/UrlGenerator.php b/core/lib/Drupal/Core/Routing/UrlGenerator.php index 75779a2..f82c1ac 100644 --- a/core/lib/Drupal/Core/Routing/UrlGenerator.php +++ b/core/lib/Drupal/Core/Routing/UrlGenerator.php @@ -7,8 +7,7 @@ namespace Drupal\Core\Routing; -use Symfony\Component\HttpKernel\Log\LoggerInterface; - +use Psr\Log\LoggerInterface; use Symfony\Cmf\Component\Routing\ProviderBasedGenerator; use Symfony\Cmf\Component\Routing\RouteProviderInterface; @@ -33,7 +32,7 @@ class UrlGenerator extends ProviderBasedGenerator { * The route provider to be searched for routes. * @param \Drupal\Core\Path\AliasManagerInterface $alias_manager * The alias manager responsible for path aliasing. - * @param \Symfony\Component\HttpKernel\Log\LoggerInterface $logger + * @param \Psr\Log\LoggerInterface $logger * An optional logger for recording errors. */ public function __construct(RouteProviderInterface $provider, AliasManagerInterface $alias_manager, LoggerInterface $logger = NULL) { diff --git a/core/lib/Drupal/Core/WatchdogLogger.php b/core/lib/Drupal/Core/WatchdogLogger.php new file mode 100644 index 0000000..0b16cc0 --- /dev/null +++ b/core/lib/Drupal/Core/WatchdogLogger.php @@ -0,0 +1,128 @@ +request = $request; + } + + /** + * {@inheritdoc} + */ + public function log($level, $message, array $context = array()) { + global $user, $base_root; + // Fill in defaults. + $context += array( + 'type' => 'system', + 'variables' => array(), + 'link' => '', + 'user' => $user, + 'uid' => isset($user->uid) ? $user->uid : 0, + 'request_uri' => $base_root . request_uri(), + 'referer' => $this->request->server->get('HTTP_REFERER', ''), + 'ip' => $this->request->getClientIP(), + 'timestamp' => time(), + ); + if (is_string($level)) { + // Convert to integer equivalent for BC and PHP syslog() compatibility. + $level = $this->mapLevel($level); + } + // Call all available loggers. + foreach ($this->loggers as $logger) { + $logger->log($level, $message, $context); + } + } + + /** + * Sets the request. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * The current request object. + */ + public function setRequest(Request $request) { + $this->request = $request; + } + + /** + * Adds a logger. + * + * @param \Psr\Log\LoggerInterface $logger + * The PSR-3 logger to add. + */ + public function addLogger(LoggerInterface $logger) { + $this->loggers[] = $logger; + } + + /** + * Converts a PSR Log level to a Watchdog log level. + * + * @param string $level + * A PSR-3 logging level string. + * + * @return int + * The corresponding Watchdog constant. + */ + protected function mapLevel($level) { + if (empty($this->levelTranslation)) { + // Use PHP constants to keep this unit-testable. + $this->levelTranslation = array( + LogLevel::EMERGENCY => LOG_EMERG, + LogLevel::ALERT => LOG_ALERT, + LogLevel::CRITICAL => LOG_CRIT, + LogLevel::ERROR => LOG_ERR, + LogLevel::WARNING => LOG_WARNING, + LogLevel::NOTICE => LOG_NOTICE, + LogLevel::INFO => LOG_INFO, + LogLevel::DEBUG => LOG_DEBUG, + ); + } + + return $this->levelTranslation[$level]; + } + +} diff --git a/core/modules/dblog/dblog.module b/core/modules/dblog/dblog.module index d28f3b7..520faeb 100644 --- a/core/modules/dblog/dblog.module +++ b/core/modules/dblog/dblog.module @@ -140,31 +140,6 @@ function _dblog_get_message_types() { } /** - * Implements hook_watchdog(). - * - * Note: Some values may be truncated to meet database column size restrictions. - */ -function dblog_watchdog(array $log_entry) { - // Remove any backtraces since they may contain an unserializable variable. - unset($log_entry['variables']['backtrace']); - - Database::getConnection('default', 'default')->insert('watchdog') - ->fields(array( - 'uid' => $log_entry['uid'], - 'type' => substr($log_entry['type'], 0, 64), - 'message' => $log_entry['message'], - 'variables' => serialize($log_entry['variables']), - 'severity' => $log_entry['severity'], - 'link' => substr($log_entry['link'], 0, 255), - 'location' => $log_entry['request_uri'], - 'referer' => $log_entry['referer'], - 'hostname' => substr($log_entry['ip'], 0, 128), - 'timestamp' => $log_entry['timestamp'], - )) - ->execute(); -} - -/** * Implements hook_form_FORM_ID_alter() for system_logging_settings(). */ function dblog_form_system_logging_settings_alter(&$form, $form_state) { diff --git a/core/modules/dblog/dblog.services.yml b/core/modules/dblog/dblog.services.yml new file mode 100644 index 0000000..174c624 --- /dev/null +++ b/core/modules/dblog/dblog.services.yml @@ -0,0 +1,6 @@ +services: + logger.watchdog.dblog: + class: Drupal\dblog\DbLogWatchdog + arguments: ['@database'] + tags: + - { name: watchdog_logger } diff --git a/core/modules/dblog/lib/Drupal/dblog/DbLogWatchdog.php b/core/modules/dblog/lib/Drupal/dblog/DbLogWatchdog.php new file mode 100644 index 0000000..713ac7f --- /dev/null +++ b/core/modules/dblog/lib/Drupal/dblog/DbLogWatchdog.php @@ -0,0 +1,61 @@ +database = $database; + } + + /** + * {@inheritdoc} + */ + public function log($level, $message, array $context = array()) { + if (isset($context['variables']['backtrace'])) { + // Remove any backtraces since they may contain an unserializable variable. + unset($context['variables']['backtrace']); + } + + $this->database + ->insert('watchdog') + ->fields(array( + 'uid' => $context['uid'], + 'type' => substr($context['type'], 0, 64), + 'message' => $message, + 'variables' => serialize($context['variables']), + 'severity' => $level, + 'link' => substr($context['link'], 0, 255), + 'location' => $context['request_uri'], + 'referer' => $context['referer'], + 'hostname' => substr($context['ip'], 0, 128), + 'timestamp' => $context['timestamp'], + )) + ->execute(); + } + +} diff --git a/core/modules/dblog/lib/Drupal/dblog/Tests/DBLogTest.php b/core/modules/dblog/lib/Drupal/dblog/Tests/DBLogTest.php index 9fcc1ee..23a8561 100644 --- a/core/modules/dblog/lib/Drupal/dblog/Tests/DBLogTest.php +++ b/core/modules/dblog/lib/Drupal/dblog/Tests/DBLogTest.php @@ -143,7 +143,7 @@ private function generateLogEntries($count, $type = 'custom', $severity = WATCHD $message = 'Log entry added to test the dblog row limit. Entry #'; for ($i = 0; $i < $count; $i++) { $log['message'] = $message . $i; - dblog_watchdog($log); + $this->container->get('logger.watchdog.dblog')->log($severity, $log['message'], $log); } } @@ -428,7 +428,7 @@ protected function testDBLogAddAndClear() { 'timestamp' => REQUEST_TIME, ); // Add a watchdog entry. - dblog_watchdog($log); + $this->container->get('logger.watchdog.dblog')->log($log['severity'], $log['message'], $log); // Make sure the table count has actually been incremented. $this->assertEqual($count + 1, db_query('SELECT COUNT(*) FROM {watchdog}')->fetchField(), format_string('dblog_watchdog() added an entry to the dblog :count', array(':count' => $count))); // Login the admin user. diff --git a/core/modules/syslog/lib/Drupal/syslog/SysLogWatchdog.php b/core/modules/syslog/lib/Drupal/syslog/SysLogWatchdog.php new file mode 100644 index 0000000..3c4e4db --- /dev/null +++ b/core/modules/syslog/lib/Drupal/syslog/SysLogWatchdog.php @@ -0,0 +1,61 @@ +config = $config_factory->get('syslog.settings'); + $facility = $this->config->get('facility'); + if ($facility === '') { + $facility = defined('LOG_LOCAL0') ? LOG_LOCAL0 : LOG_USER; + } + openlog($this->config->get('identity'), LOG_NDELAY, $facility); + } + + /** + * {@inheritdoc} + */ + public function log($level, $message, array $context = array()) { + global $base_url; + + $entry = strtr($this->config->get('format'), array( + '!base_url' => $base_url, + '!timestamp' => $context['timestamp'], + '!type' => $context['type'], + '!ip' => $context['ip'], + '!request_uri' => $context['request_uri'], + '!referer' => $context['referer'], + '!uid' => $context['uid'], + '!link' => strip_tags($context['link']), + '!message' => strip_tags(!isset($context['variables']) ? $message : strtr($message, $context['variables'])), + )); + + syslog($level, $entry); + } + +} diff --git a/core/modules/syslog/syslog.module b/core/modules/syslog/syslog.module index 8af77c1..3d152fe 100644 --- a/core/modules/syslog/syslog.module +++ b/core/modules/syslog/syslog.module @@ -103,36 +103,3 @@ function syslog_facility_list() { LOG_LOCAL7 => 'LOG_LOCAL7', ); } - -/** - * Implements hook_watchdog(). - */ -function syslog_watchdog(array $log_entry) { - global $base_url; - - $log_init = &drupal_static(__FUNCTION__, FALSE); - $config = config('syslog.settings'); - - if (!$log_init) { - $log_init = TRUE; - $facility = $config->get('facility'); - if ($facility === '') { - $facility = defined('LOG_LOCAL0') ? LOG_LOCAL0 : LOG_USER; - } - openlog($config->get('identity'), LOG_NDELAY, $facility); - } - - $message = strtr($config->get('format'), array( - '!base_url' => $base_url, - '!timestamp' => $log_entry['timestamp'], - '!type' => $log_entry['type'], - '!ip' => $log_entry['ip'], - '!request_uri' => $log_entry['request_uri'], - '!referer' => $log_entry['referer'], - '!uid' => $log_entry['uid'], - '!link' => strip_tags($log_entry['link']), - '!message' => strip_tags(!isset($log_entry['variables']) ? $log_entry['message'] : strtr($log_entry['message'], $log_entry['variables'])), - )); - - syslog($log_entry['severity'], $message); -} diff --git a/core/modules/syslog/syslog.services.yml b/core/modules/syslog/syslog.services.yml new file mode 100644 index 0000000..5105b32 --- /dev/null +++ b/core/modules/syslog/syslog.services.yml @@ -0,0 +1,6 @@ +services: + logger.watchdog.syslog: + class: Drupal\syslog\SysLogWatchdog + arguments: ['@config.factory'] + tags: + - { name: watchdog_logger }