diff --git a/core/core.services.yml b/core/core.services.yml index 04e6ec0..f3ffeb0 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -119,6 +119,16 @@ services: factory_method: get factory_service: keyvalue arguments: [state] + watchdog.factory: + class: Drupal\Core\Watchdog\WatchdogChannelFactory + calls: + - [setContainer, ['@service_container']] + watchdog.channel.default: + class: Drupal\Core\Watchdog\WatchdogChannel + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } queue: class: Drupal\Core\Queue\QueueFactory arguments: ['@settings'] @@ -169,7 +179,7 @@ services: arguments: ['@service_container'] controller_resolver: class: Drupal\Core\Controller\ControllerResolver - arguments: ['@service_container'] + arguments: ['@service_container', '@watchdog.channel.default'] http_kernel: class: Drupal\Core\HttpKernel arguments: ['@event_dispatcher', '@service_container', '@controller_resolver'] @@ -214,7 +224,7 @@ services: - [setFinalMatcher, ['@router.matcher.final_matcher']] url_generator: class: Drupal\Core\Routing\UrlGenerator - arguments: ['@router.route_provider', '@path_processor_manager', '@config.factory', '@settings'] + arguments: ['@router.route_provider', '@path_processor_manager', '@config.factory', '@settings', '@watchdog.channel.default'] calls: - [setRequest, ['@?request']] tags: @@ -231,6 +241,7 @@ services: arguments: ['@router.request_context', '@legacy_url_matcher', '@legacy_generator'] router: class: Symfony\Cmf\Component\Routing\ChainRouter + arguments: ['@watchdog.channel.default'] calls: - [setContext, ['@router.request_context']] - [add, ['@router.dynamic']] @@ -403,7 +414,7 @@ services: class: Symfony\Component\HttpKernel\EventListener\ExceptionListener tags: - { name: event_subscriber } - arguments: [['@exception_controller', execute]] + arguments: [['@exception_controller', execute], '@watchdog.channel.default'] path_processor_manager: class: Drupal\Core\PathProcessor\PathProcessorManager path_processor_decode: diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index cf0e3dd..1eb3295 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -1328,7 +1328,7 @@ function drupal_serve_page_from_cache(stdClass $cache, Response $response, Reque * Defines the critical hooks that force modules to always be loaded. */ function bootstrap_hooks() { - return array('watchdog'); + return array(); } /** @@ -1542,57 +1542,13 @@ function watchdog_exception($type, Exception $exception, $message = NULL, $varia * A link to associate with the message. * * @see watchdog_severity_levels() - * @see hook_watchdog() */ 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' => '', - 'referer' => '', - 'ip' => '', - // Request time isn't accurate for long processes, use time() instead. - 'timestamp' => time(), - ); - - try { - $request = Drupal::request(); - $log_entry['request_uri'] = $request->getUri(); - $log_entry['referer'] = $request->headers->get('Referer', ''); - $log_entry['ip'] = $request->getClientIP(); - } - catch (\InvalidArgumentException $e) { - // We are not in a request context. - } - - // 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; + $variables = $variables ?: array(); + if ($link) { + $variables['link'] = $link; } + Drupal::service('watchdog.factory')->getLogger($type)->log($severity, $message, $variables); } /** diff --git a/core/lib/Drupal/Core/Controller/ControllerResolver.php b/core/lib/Drupal/Core/Controller/ControllerResolver.php index 385f198..feb8bb4 100644 --- a/core/lib/Drupal/Core/Controller/ControllerResolver.php +++ b/core/lib/Drupal/Core/Controller/ControllerResolver.php @@ -7,8 +7,8 @@ namespace Drupal\Core\Controller; +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 9af0c74..acb34cc 100644 --- a/core/lib/Drupal/Core/CoreBundle.php +++ b/core/lib/Drupal/Core/CoreBundle.php @@ -18,6 +18,7 @@ use Drupal\Core\DependencyInjection\Compiler\RegisterServicesForDestructionPass; use Drupal\Core\DependencyInjection\Compiler\RegisterStringTranslatorsPass; use Drupal\Core\DependencyInjection\Compiler\RegisterBreadcrumbBuilderPass; +use Drupal\Core\DependencyInjection\Compiler\RegisterWatchdogLoggersPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Reference; @@ -67,6 +68,8 @@ public function build(ContainerBuilder $container) { // Add the compiler pass that will process the tagged breadcrumb builder // services. $container->addCompilerPass(new RegisterBreadcrumbBuilderPass()); + // 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..37fdee0 --- /dev/null +++ b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterWatchdogLoggersPass.php @@ -0,0 +1,34 @@ +findTaggedServiceIds('watchdog_channel') as $id => $attributes) { + $definitions[] = $container->getDefinition($id); + } + // Loop through all available logger services (eg dblog, syslog) and add + // the available logging channels + foreach ($container->findTaggedServiceIds('watchdog_logger') as $id => $attributes) { + $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0; + foreach ($definitions as $definition) { + $definition->addMethodCall('addLogger', array(new Reference($id), $priority)); + } + } + } + +} diff --git a/core/lib/Drupal/Core/Routing/UrlGenerator.php b/core/lib/Drupal/Core/Routing/UrlGenerator.php index 04c2c17..d129a39 100644 --- a/core/lib/Drupal/Core/Routing/UrlGenerator.php +++ b/core/lib/Drupal/Core/Routing/UrlGenerator.php @@ -7,8 +7,8 @@ namespace Drupal\Core\Routing; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpKernel\Log\LoggerInterface; use Symfony\Component\Routing\Route as SymfonyRoute; use Symfony\Component\Routing\Exception\RouteNotFoundException; @@ -74,7 +74,7 @@ class UrlGenerator extends ProviderBasedGenerator implements PathBasedGeneratorI * 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, OutboundPathProcessorInterface $path_processor, ConfigFactory $config, Settings $settings, LoggerInterface $logger = NULL) { diff --git a/core/lib/Drupal/Core/Watchdog/WatchdogChannel.php b/core/lib/Drupal/Core/Watchdog/WatchdogChannel.php new file mode 100644 index 0000000..6cb3171 --- /dev/null +++ b/core/lib/Drupal/Core/Watchdog/WatchdogChannel.php @@ -0,0 +1,147 @@ +channel = $channel; + } + + /** + * {@inheritdoc} + */ + public function log($level, $message, array $context = array()) { + // @todo Retrieve from request once https://drupal.org/node/1890878 is in. + global $user; + $context += array( + 'type' => $this->channel, + 'link' => '', + 'user' => $user, + 'uid' => isset($user->uid) ? $user->uid : 0, + 'request_uri' => $this->request->server->get('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->sortLoggers() 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. + * @param int $priority + * The priority of the logger being added. + */ + public function addLogger(LoggerInterface $logger, $priority = 0) { + $this->loggers[$priority][] = $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]; + } + + /** + * Sorts loggers according to priority. + * + * @return array + * An array of sorted loggers by priority. + */ + protected function sortLoggers() { + $sorted = array(); + krsort($this->loggers); + + foreach ($this->loggers as $loggers) { + $sorted = array_merge($sorted, $loggers); + } + return $sorted; + } + +} diff --git a/core/lib/Drupal/Core/Watchdog/WatchdogChannelFactory.php b/core/lib/Drupal/Core/Watchdog/WatchdogChannelFactory.php new file mode 100644 index 0000000..8e83f0e --- /dev/null +++ b/core/lib/Drupal/Core/Watchdog/WatchdogChannelFactory.php @@ -0,0 +1,35 @@ +container->has($channel_service)) { + return $this->container->get($channel_service); + } + else { + return $this->container->get('watchdog.channel.default'); + } + } + +} diff --git a/core/lib/Drupal/Core/Watchdog/WatchdogLoggerBase.php b/core/lib/Drupal/Core/Watchdog/WatchdogLoggerBase.php new file mode 100644 index 0000000..4016bf7 --- /dev/null +++ b/core/lib/Drupal/Core/Watchdog/WatchdogLoggerBase.php @@ -0,0 +1,62 @@ + 1) { + $has_ps3 = TRUE; + // Replace PS3 messages containing placeholders. + $message = preg_replace('/\{(.*)\}/', '@$1', $message); + } + foreach ($context as $key => $variable) { + // PSR3 style placeholders. + if ($has_ps3) { + // Keys are not prefixed with anything according to PSR3 specs. + // If the message is "User {username} created" the variable key will be + // just "username". + if (strpos($message, '@' . $key) !== FALSE) { + $key = '@' . $key; + } + } + elseif (strpos($key, '@') !== 0 && strpos($key, '%') !== 0 && strpos($key, '!') !== 0) { + // This is not a replacement variable for the message. + continue; + } + // The key is now in \Drupal\Component\Utility\String::format() style. + $variables[$key] = $variable; + } + $context['variables'] = $variables; + } + +} diff --git a/core/modules/action/action.services.yml b/core/modules/action/action.services.yml new file mode 100644 index 0000000..bd2b3bb --- /dev/null +++ b/core/modules/action/action.services.yml @@ -0,0 +1,8 @@ +services: + watchdog.channel.action: + class: Drupal\Core\Watchdog\WatchdogChannel + arguments: ['action'] + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } diff --git a/core/modules/aggregator/aggregator.services.yml b/core/modules/aggregator/aggregator.services.yml index 639ed2d..d3056e8 100644 --- a/core/modules/aggregator/aggregator.services.yml +++ b/core/modules/aggregator/aggregator.services.yml @@ -8,3 +8,10 @@ services: plugin.manager.aggregator.processor: class: Drupal\aggregator\Plugin\AggregatorPluginManager arguments: [processor, '@container.namespaces'] + watchdog.channel.aggregator: + class: Drupal\Core\Watchdog\WatchdogChannel + arguments: ['aggregator'] + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } diff --git a/core/modules/block/custom_block/custom_block.services.yml b/core/modules/block/custom_block/custom_block.services.yml new file mode 100644 index 0000000..7aa159d --- /dev/null +++ b/core/modules/block/custom_block/custom_block.services.yml @@ -0,0 +1,8 @@ +services: + watchdog.channel.custom_block: + class: Drupal\Core\Watchdog\WatchdogChannel + arguments: ['custom block'] + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } diff --git a/core/modules/contact/contact.services.yml b/core/modules/contact/contact.services.yml new file mode 100644 index 0000000..4933c74 --- /dev/null +++ b/core/modules/contact/contact.services.yml @@ -0,0 +1,8 @@ +services: + watchdog.channel.contact: + class: Drupal\Core\Watchdog\WatchdogChannel + arguments: ['contact'] + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } diff --git a/core/modules/dblog/dblog.module b/core/modules/dblog/dblog.module index 202cfcf..b9fcc82 100644 --- a/core/modules/dblog/dblog.module +++ b/core/modules/dblog/dblog.module @@ -138,31 +138,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..de7d173 --- /dev/null +++ b/core/modules/dblog/dblog.services.yml @@ -0,0 +1,6 @@ +services: + watchdog.dblog: + class: Drupal\dblog\Watchdog\DbLog + arguments: ['@database'] + tags: + - { name: watchdog_logger } diff --git a/core/modules/dblog/lib/Drupal/dblog/Tests/DbLogTest.php b/core/modules/dblog/lib/Drupal/dblog/Tests/DbLogTest.php index e619fff..32c1e27 100644 --- a/core/modules/dblog/lib/Drupal/dblog/Tests/DbLogTest.php +++ b/core/modules/dblog/lib/Drupal/dblog/Tests/DbLogTest.php @@ -145,7 +145,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('watchdog.dblog')->log($severity, $log['message'], $log); } } @@ -430,7 +430,7 @@ protected function testDBLogAddAndClear() { 'timestamp' => REQUEST_TIME, ); // Add a watchdog entry. - dblog_watchdog($log); + $this->container->get('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/dblog/lib/Drupal/dblog/Watchdog/DbLog.php b/core/modules/dblog/lib/Drupal/dblog/Watchdog/DbLog.php new file mode 100644 index 0000000..8533812 --- /dev/null +++ b/core/modules/dblog/lib/Drupal/dblog/Watchdog/DbLog.php @@ -0,0 +1,61 @@ +database = $database; + } + + /** + * {@inheritdoc} + */ + public function log($level, $message, array $context = array()) { + // Remove any backtraces since they may contain an unserializable variable. + unset($context['backtrace']); + + $this->parseMessagePlaceholders($message, $context); + + $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/file/file.services.yml b/core/modules/file/file.services.yml index 2ded051..824077e 100644 --- a/core/modules/file/file.services.yml +++ b/core/modules/file/file.services.yml @@ -2,3 +2,10 @@ services: file.usage: class: Drupal\file\FileUsage\DatabaseFileUsageBackend arguments: ['@database'] + watchdog.channel.file: + class: Drupal\Core\Watchdog\WatchdogChannel + arguments: ['file'] + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } diff --git a/core/modules/filter/filter.services.yml b/core/modules/filter/filter.services.yml index 306c6aa..10e6b9a 100644 --- a/core/modules/filter/filter.services.yml +++ b/core/modules/filter/filter.services.yml @@ -17,3 +17,10 @@ services: plugin.manager.filter: class: Drupal\filter\FilterPluginManager arguments: ['@container.namespaces'] + watchdog.channel.filter: + class: Drupal\Core\Watchdog\WatchdogChannel + arguments: ['filter'] + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } diff --git a/core/modules/forum/forum.services.yml b/core/modules/forum/forum.services.yml index 19033e8..c3ff6cd 100644 --- a/core/modules/forum/forum.services.yml +++ b/core/modules/forum/forum.services.yml @@ -4,3 +4,10 @@ services: arguments: ['@plugin.manager.entity', '@config.factory'] tags: - { name: breadcrumb_builder, priority: 1001 } + watchdog.channel.forum: + class: Drupal\Core\Watchdog\WatchdogChannel + arguments: ['forum'] + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } diff --git a/core/modules/image/image.services.yml b/core/modules/image/image.services.yml new file mode 100644 index 0000000..6036a0d --- /dev/null +++ b/core/modules/image/image.services.yml @@ -0,0 +1,8 @@ +services: + watchdog.channel.image: + class: Drupal\Core\Watchdog\WatchdogChannel + arguments: ['image'] + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } diff --git a/core/modules/language/language.services.yml b/core/modules/language/language.services.yml index d6599b3..1b6615d 100644 --- a/core/modules/language/language.services.yml +++ b/core/modules/language/language.services.yml @@ -5,3 +5,10 @@ services: tags: - { name: path_processor_inbound, priority: 300 } - { name: path_processor_outbound, priority: 100 } + watchdog.channel.language: + class: Drupal\Core\Watchdog\WatchdogChannel + arguments: ['language'] + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } diff --git a/core/modules/locale/locale.services.yml b/core/modules/locale/locale.services.yml index f632704..e0ac468 100644 --- a/core/modules/locale/locale.services.yml +++ b/core/modules/locale/locale.services.yml @@ -16,3 +16,10 @@ services: tags: - { name: string_translator } - { name: needs_destruction } + watchdog.channel.locale: + class: Drupal\Core\Watchdog\WatchdogChannel + arguments: ['locale'] + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } diff --git a/core/modules/menu/menu.services.yml b/core/modules/menu/menu.services.yml index f417d6f..dbe6840 100644 --- a/core/modules/menu/menu.services.yml +++ b/core/modules/menu/menu.services.yml @@ -7,3 +7,10 @@ services: class: Drupal\menu\Access\DeleteMenuAccessCheck tags: - { name: access_check } + watchdog.channel.menu: + class: Drupal\Core\Watchdog\WatchdogChannel + arguments: ['menu'] + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } diff --git a/core/modules/node/node.services.yml b/core/modules/node/node.services.yml new file mode 100644 index 0000000..588369e --- /dev/null +++ b/core/modules/node/node.services.yml @@ -0,0 +1,15 @@ +services: + watchdog.channel.content: + class: Drupal\Core\Watchdog\WatchdogChannel + arguments: ['content'] + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } + watchdog.channel.node: + class: Drupal\Core\Watchdog\WatchdogChannel + arguments: ['node'] + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } diff --git a/core/modules/picture/picture.service.yml b/core/modules/picture/picture.service.yml new file mode 100644 index 0000000..b3403b3 --- /dev/null +++ b/core/modules/picture/picture.service.yml @@ -0,0 +1,8 @@ +services: + watchdog.channel.picture: + class: Drupal\Core\Watchdog\WatchdogChannel + arguments: ['picture'] + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } diff --git a/core/modules/rest/lib/Drupal/rest/Tests/DBLogTest.php b/core/modules/rest/lib/Drupal/rest/Tests/DBLogTest.php index f3e0eda..92781f0 100644 --- a/core/modules/rest/lib/Drupal/rest/Tests/DBLogTest.php +++ b/core/modules/rest/lib/Drupal/rest/Tests/DBLogTest.php @@ -19,7 +19,7 @@ class DBLogTest extends RESTTestBase { * * @var array */ - public static $modules = array('hal', 'rest', 'dblog'); + public static $modules = array('hal', 'rest', 'dblog', 'rest_test'); public static function getInfo() { return array( diff --git a/core/modules/rest/rest.services.yml b/core/modules/rest/rest.services.yml index 97817ad..ba9c37f 100644 --- a/core/modules/rest/rest.services.yml +++ b/core/modules/rest/rest.services.yml @@ -20,3 +20,10 @@ services: rest.link_manager.relation: class: Drupal\rest\LinkManager\RelationLinkManager arguments: ['@cache.cache'] + watchdog.channel.rest: + class: Drupal\Core\Watchdog\WatchdogChannel + arguments: ['rest'] + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } diff --git a/core/modules/rest/tests/modules/rest_test/rest_test.info.yml b/core/modules/rest/tests/modules/rest_test/rest_test.info.yml new file mode 100644 index 0000000..1d337aa --- /dev/null +++ b/core/modules/rest/tests/modules/rest_test/rest_test.info.yml @@ -0,0 +1,7 @@ +name: 'REST test' +type: module +description: 'Test module for REST testing.' +package: Testing +version: VERSION +core: 8.x +hidden: true diff --git a/core/modules/rest/tests/modules/rest_test/rest_test.module b/core/modules/rest/tests/modules/rest_test/rest_test.module new file mode 100644 index 0000000..b3d9bbc --- /dev/null +++ b/core/modules/rest/tests/modules/rest_test/rest_test.module @@ -0,0 +1 @@ +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; + $variables = array(); + // Populate the $context['variables'] with the message placeholders. + $this->parseMessagePlaceholders($message, $context); + foreach ($context['variables'] as $key => $variable) { + // A message placeholder will either be format_string() style. + if (strpos($key, '@') === 0 || strpos($key, '%') === 0 || strpos($key, '!') === 0) { + $variables[$key] = $variable; + } + } + + $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(empty($variables) ? $message : strtr($message, $variables)), + )); + + syslog($level, $entry); + } + +} diff --git a/core/modules/syslog/syslog.module b/core/modules/syslog/syslog.module index fe781c3..814edf0 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..fb081f5 --- /dev/null +++ b/core/modules/syslog/syslog.services.yml @@ -0,0 +1,6 @@ +services: + watchdog.syslog: + class: Drupal\syslog\Watchdog\SysLog + arguments: ['@config.factory'] + tags: + - { name: watchdog_logger } diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiInfoTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiInfoTest.php index cf7d9cf..014b657 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiInfoTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiInfoTest.php @@ -50,7 +50,7 @@ function testEntityInfoChanges() { * * @see entity_cache_test_watchdog() */ - function testEntityInfoCacheWatchdog() { + function testEntityInfoCacheModulesEnabled() { module_enable(array('entity_cache_test')); $info = \Drupal::state()->get('entity_cache_test'); $this->assertEqual($info['label'], 'Entity Cache Test', 'Entity info label is correct.'); diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php index e9e69c5..a46d3c4 100644 --- a/core/modules/system/system.api.php +++ b/core/modules/system/system.api.php @@ -1772,94 +1772,6 @@ function hook_custom_theme() { } /** - * Log an event message. - * - * This hook allows modules to route log events to custom destinations, such as - * SMS, Email, pager, syslog, ...etc. - * - * @param array $log_entry - * An associative array containing the following keys: - * - type: The type of message for this entry. - * - user: The user object for the user who was logged in when the event - * happened. - * - uid: The user ID for the user who was logged in when the event happened. - * - request_uri: The request URI for the page the event happened in. - * - referer: The page that referred the user to the page where the event - * occurred. - * - ip: The IP address where the request for the page came from. - * - timestamp: The UNIX timestamp of the date/time the event occurred. - * - severity: The severity of the message; one of the following values as - * defined in @link http://www.faqs.org/rfcs/rfc3164.html RFC 3164: @endlink - * - WATCHDOG_EMERGENCY: Emergency, system is unusable. - * - WATCHDOG_ALERT: Alert, action must be taken immediately. - * - WATCHDOG_CRITICAL: Critical conditions. - * - WATCHDOG_ERROR: Error conditions. - * - WATCHDOG_WARNING: Warning conditions. - * - WATCHDOG_NOTICE: Normal but significant conditions. - * - WATCHDOG_INFO: Informational messages. - * - WATCHDOG_DEBUG: Debug-level messages. - * - link: An optional link provided by the module that called the watchdog() - * function. - * - message: The text of the message to be logged. Variables in the message - * are indicated by using placeholder strings alongside the variables - * argument to declare the value of the placeholders. See t() for - * documentation on how the message and variable parameters interact. - * - variables: An array of variables to be inserted into the message on - * display. Will be NULL or missing if a message is already translated or if - * the message is not possible to translate. - */ -function hook_watchdog(array $log_entry) { - global $base_url; - $language_interface = language(\Drupal\Core\Language\Language::TYPE_INTERFACE); - - $severity_list = array( - WATCHDOG_EMERGENCY => t('Emergency'), - WATCHDOG_ALERT => t('Alert'), - WATCHDOG_CRITICAL => t('Critical'), - WATCHDOG_ERROR => t('Error'), - WATCHDOG_WARNING => t('Warning'), - WATCHDOG_NOTICE => t('Notice'), - WATCHDOG_INFO => t('Info'), - WATCHDOG_DEBUG => t('Debug'), - ); - - $to = 'someone@example.com'; - $params = array(); - $params['subject'] = t('[@site_name] @severity_desc: Alert from your web site', array( - '@site_name' => config('system.site')->get('name'), - '@severity_desc' => $severity_list[$log_entry['severity']], - )); - - $params['message'] = "\nSite: @base_url"; - $params['message'] .= "\nSeverity: (@severity) @severity_desc"; - $params['message'] .= "\nTimestamp: @timestamp"; - $params['message'] .= "\nType: @type"; - $params['message'] .= "\nIP Address: @ip"; - $params['message'] .= "\nRequest URI: @request_uri"; - $params['message'] .= "\nReferrer URI: @referer_uri"; - $params['message'] .= "\nUser: (@uid) @name"; - $params['message'] .= "\nLink: @link"; - $params['message'] .= "\nMessage: \n\n@message"; - - $params['message'] = t($params['message'], array( - '@base_url' => $base_url, - '@severity' => $log_entry['severity'], - '@severity_desc' => $severity_list[$log_entry['severity']], - '@timestamp' => format_date($log_entry['timestamp']), - '@type' => $log_entry['type'], - '@ip' => $log_entry['ip'], - '@request_uri' => $log_entry['request_uri'], - '@referer_uri' => $log_entry['referer'], - '@uid' => $log_entry['uid'], - '@name' => $log_entry['user']->name, - '@link' => strip_tags($log_entry['link']), - '@message' => strip_tags($log_entry['message']), - )); - - drupal_mail('emaillog', 'entry', $to, $language_interface->langcode, $params); -} - -/** * Prepare a message based on parameters; called from drupal_mail(). * * Note that hook_mail(), unlike hook_mail_alter(), is only called on the diff --git a/core/modules/system/system.module b/core/modules/system/system.module index 7a1b8d4..065442c 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -2918,8 +2918,8 @@ function system_rebuild_module_data() { * Refreshes the list of bootstrap modules. * * This is called internally by module_enable/disable() to flag modules that - * implement hooks used during bootstrap, such as hook_watchdog(). These modules - * are loaded earlier to invoke the hooks. + * implement hooks used during bootstrap. These modules are loaded earlier to + * invoke the hooks. */ function _system_update_bootstrap_status() { $bootstrap_modules = array(); diff --git a/core/modules/system/system.services.yml b/core/modules/system/system.services.yml index 6aefa00..3a4fc73 100644 --- a/core/modules/system/system.services.yml +++ b/core/modules/system/system.services.yml @@ -17,3 +17,73 @@ services: class: Drupal\system\Routing\RouteSubscriber tags: - { name: event_subscriber } + watchdog.channel.access_denied: + class: Drupal\Core\Watchdog\WatchdogChannel + arguments: ['access denied'] + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } + watchdog.channel.ajax: + class: Drupal\Core\Watchdog\WatchdogChannel + arguments: ['ajax'] + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } + watchdog.channel.cron: + class: Drupal\Core\Watchdog\WatchdogChannel + arguments: ['cron'] + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } + watchdog.channel.file_system: + class: Drupal\Core\Watchdog\WatchdogChannel + arguments: ['file system'] + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } + watchdog.channel.form: + class: Drupal\Core\Watchdog\WatchdogChannel + arguments: ['form'] + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } + watchdog.channel.mail: + class: Drupal\Core\Watchdog\WatchdogChannel + arguments: ['mail'] + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } + watchdog.channel.theme: + class: Drupal\Core\Watchdog\WatchdogChannel + arguments: ['theme'] + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } + watchdog.channel.page_not_found: + class: Drupal\Core\Watchdog\WatchdogChannel + arguments: ['page not found'] + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } + watchdog.channel.php: + class: Drupal\Core\Watchdog\WatchdogChannel + arguments: ['php'] + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } + watchdog.channel.security: + class: Drupal\Core\Watchdog\WatchdogChannel + arguments: ['security'] + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } diff --git a/core/modules/system/tests/modules/entity_cache_test/entity_cache_test.module b/core/modules/system/tests/modules/entity_cache_test/entity_cache_test.module index 962114c..2d934b3 100644 --- a/core/modules/system/tests/modules/entity_cache_test/entity_cache_test.module +++ b/core/modules/system/tests/modules/entity_cache_test/entity_cache_test.module @@ -6,7 +6,7 @@ */ /** - * Implements hook_watchdog(). + * Implements hook_modules_enabled(). * * This hook is called during module_enable() and since this hook * implementation is invoked, we have to expect that this module and dependent @@ -14,13 +14,11 @@ * retrieve the entity information that has been registered by the required * dependency module. * - * @see EnableDisableTestCase::testEntityCache() + * @see EntityApiInfoTest::testEntityInfoCacheModulesEnabled() */ -function entity_cache_test_watchdog($log_entry) { - if ($log_entry['type'] == 'system' && $log_entry['message'] == '%module module installed.') { - $info = entity_get_info('entity_cache_test'); - // Store the information in a system variable to analyze it later in the - // test case. - Drupal::state()->set('entity_cache_test', $info); - } +function entity_cache_test_modules_enabled($modules_enabled) { + $info = entity_get_info('entity_cache_test'); + // Store the information in a system variable to analyze it later in the + // test case. + Drupal::state()->set('entity_cache_test', $info); } diff --git a/core/modules/taxonomy/taxonomy.services.yml b/core/modules/taxonomy/taxonomy.services.yml new file mode 100644 index 0000000..4adc16a --- /dev/null +++ b/core/modules/taxonomy/taxonomy.services.yml @@ -0,0 +1,8 @@ +services: + watchdog.channel.taxonomy: + class: Drupal\Core\Watchdog\WatchdogChannel + arguments: ['taxonomy'] + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } diff --git a/core/modules/tracker/tracker.services.yml b/core/modules/tracker/tracker.services.yml new file mode 100644 index 0000000..dbb26b0 --- /dev/null +++ b/core/modules/tracker/tracker.services.yml @@ -0,0 +1,8 @@ +services: + watchdog.channel.tracker: + class: Drupal\Core\Watchdog\WatchdogChannel + arguments: ['tracker'] + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } diff --git a/core/modules/user/user.services.yml b/core/modules/user/user.services.yml index 6fb7d47..66fa737 100644 --- a/core/modules/user/user.services.yml +++ b/core/modules/user/user.services.yml @@ -25,3 +25,10 @@ services: class: Drupal\user\EventSubscriber\MaintenanceModeSubscriber tags: - { name: event_subscriber } + watchdog.channel.user: + class: Drupal\Core\Watchdog\WatchdogChannel + arguments: ['user'] + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } diff --git a/core/modules/views/views.services.yml b/core/modules/views/views.services.yml index d5ab9d9..354b2ee 100644 --- a/core/modules/views/views.services.yml +++ b/core/modules/views/views.services.yml @@ -90,3 +90,10 @@ services: class: Drupal\views\ViewsAccessCheck tags: - { name: 'access_check' } + watchdog.channel.views: + class: Drupal\Core\Watchdog\WatchdogChannel + arguments: ['views'] + calls: + - [setRequest, ['@?request']] + tags: + - { name: watchdog_channel } diff --git a/core/tests/Drupal/Tests/Core/Watchdog/WatchdogLoggerBaseTest.php b/core/tests/Drupal/Tests/Core/Watchdog/WatchdogLoggerBaseTest.php new file mode 100644 index 0000000..b586c48 --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Watchdog/WatchdogLoggerBaseTest.php @@ -0,0 +1,76 @@ + 'Watchdog logger base', + 'description' => 'Unit tests for the watchdog logger base.', + 'group' => 'Watchdog', + ); + } + + /** + * {@inheritdoc} + */ + protected function setUp() { + $this->logger = $this->getMockForAbstractClass('Drupal\Core\Watchdog\WatchdogLoggerBase'); + } + + /** + * Test for WatchdogLoggerBase::parseMessagePlaceholders() + * + * @param array $value + * An array containing: + * - message: A string that contains a message with placeholders. + * - context: An array with placeholder values. + * @param array $expected + * An array with the expected values after the test has run. + * - message: The expected parsed message. + * - context: The expected values of the placeholders. + * + * @dataProvider providerTestParseMessagePlaceholders + */ + public function testParseMessagePlaceholders(array $value, array $expected) { + $class = new \ReflectionClass('Drupal\Core\Watchdog\WatchdogLoggerBase'); + $method = $class->getMethod('parseMessagePlaceholders'); + $method->setAccessible(TRUE); + $method->invokeArgs($this->logger, array(&$value['message'], &$value['context'])); + $this->assertEquals($expected['message'], $value['message']); + $this->assertEquals($expected['context'], $value['context']['variables']); + } + + /** + * Data provider for testParseMessagePlaceholders(). + */ + public function providerTestParseMessagePlaceholders() { + return array( + // PS3 only message. + array( + array('message' => 'User {username} created', 'context' => array('username' => 'rootatwc')), + array('message' => 'User @username created', 'context' => array('@username' => 'rootatwc')), + ), + // PS3 style mixed in a format_string style message. + array( + array('message' => 'User {username} created @time', 'context' => array('username' => 'rootatwc', '@time' => 'now')), + array('message' => 'User @username created @time', 'context' => array('@username' => 'rootatwc', '@time' => 'now')), + ), + // format_string style message only. + array( + array('message' => 'User @username created', 'context' => array('@username' => 'rootatwc')), + array('message' => 'User @username created', 'context' => array('@username' => 'rootatwc')), + ), + ); + } + +}