* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Bundle\MonologBundle\DependencyInjection; use Symfony\Component\HttpKernel\DependencyInjection\Extension; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; /** * MonologExtension is an extension for the Monolog library. * * @author Jordi Boggiano * @author Christophe Coevoet */ class MonologExtension extends Extension { private $nestedHandlers = array(); /** * Loads the Monolog configuration. * * @param array $configs An array of configuration settings * @param ContainerBuilder $container A ContainerBuilder instance */ public function load(array $configs, ContainerBuilder $container) { $configuration = $this->getConfiguration($configs, $container); $config = $this->processConfiguration($configuration, $configs); if (isset($config['handlers'])) { $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('monolog.xml'); $container->setAlias('logger', 'monolog.logger'); $handlers = array(); foreach ($config['handlers'] as $name => $handler) { $handlers[] = array( 'id' => $this->buildHandler($container, $name, $handler), 'priority' => $handler['priority'], 'channels' => isset($handler['channels']) ? $handler['channels'] : null ); } $handlers = array_reverse($handlers); uasort($handlers, function($a, $b) { if ($a['priority'] == $b['priority']) { return 0; } return $a['priority'] < $b['priority'] ? -1 : 1; }); $handlersToChannels = array(); foreach ($handlers as $handler) { if (!in_array($handler['id'], $this->nestedHandlers)) { $handlersToChannels[$handler['id']] = $handler['channels']; } } $container->setParameter('monolog.handlers_to_channels', $handlersToChannels); $this->addClassesToCompile(array( 'Monolog\\Formatter\\FormatterInterface', 'Monolog\\Formatter\\LineFormatter', 'Monolog\\Handler\\HandlerInterface', 'Monolog\\Handler\\AbstractHandler', 'Monolog\\Handler\\AbstractProcessingHandler', 'Monolog\\Handler\\StreamHandler', 'Monolog\\Handler\\FingersCrossedHandler', 'Monolog\\Handler\\TestHandler', 'Monolog\\Logger', 'Symfony\\Bridge\\Monolog\\Logger', 'Symfony\\Bridge\\Monolog\\Handler\\DebugHandler', )); } } /** * Returns the base path for the XSD files. * * @return string The XSD base path */ public function getXsdValidationBasePath() { return __DIR__.'/../Resources/config/schema'; } public function getNamespace() { return 'http://symfony.com/schema/dic/monolog'; } private function buildHandler(ContainerBuilder $container, $name, array $handler) { $handlerId = $this->getHandlerId($name); $definition = new Definition(sprintf('%%monolog.handler.%s.class%%', $handler['type'])); $handler['level'] = is_int($handler['level']) ? $handler['level'] : constant('Monolog\Logger::'.strtoupper($handler['level'])); switch ($handler['type']) { case 'service': $container->setAlias($handlerId, $handler['id']); return $handlerId; case 'stream': $definition->setArguments(array( $handler['path'], $handler['level'], $handler['bubble'], )); break; case 'firephp': $definition->setArguments(array( $handler['level'], $handler['bubble'], )); $definition->addTag('kernel.event_listener', array('event' => 'kernel.response', 'method' => 'onKernelResponse')); break; case 'gelf': if (isset($handler['publisher']['id'])) { $publisherId = $handler['publisher']['id']; } else { $publisher = new Definition("%monolog.gelf.publisher.class%", array( $handler['publisher']['hostname'], $handler['publisher']['port'], $handler['publisher']['chunk_size'], )); $publisherId = 'monolog.gelf.publisher'; $publisher->setPublic(false); $container->setDefinition($publisherId, $publisher); } $definition->setArguments(array( new Reference($publisherId), $handler['level'], $handler['bubble'], )); break; case 'chromephp': $definition->setArguments(array( $handler['level'], $handler['bubble'], )); $definition->addTag('kernel.event_listener', array('event' => 'kernel.response', 'method' => 'onKernelResponse')); break; case 'rotating_file': $definition->setArguments(array( $handler['path'], $handler['max_files'], $handler['level'], $handler['bubble'], )); break; case 'fingers_crossed': $handler['action_level'] = is_int($handler['action_level']) ? $handler['action_level'] : constant('Monolog\Logger::'.strtoupper($handler['action_level'])); $nestedHandlerId = $this->getHandlerId($handler['handler']); $this->nestedHandlers[] = $nestedHandlerId; if (isset($handler['activation_strategy'])) { $activation = new Reference($handler['activation_strategy']); } else { $activation = $handler['action_level']; } $definition->setArguments(array( new Reference($nestedHandlerId), $activation, $handler['buffer_size'], $handler['bubble'], $handler['stop_buffering'], )); break; case 'buffer': $nestedHandlerId = $this->getHandlerId($handler['handler']); $this->nestedHandlers[] = $nestedHandlerId; $definition->setArguments(array( new Reference($nestedHandlerId), $handler['buffer_size'], $handler['level'], $handler['bubble'], )); break; case 'group': $references = array(); foreach ($handler['members'] as $nestedHandler) { $nestedHandlerId = $this->getHandlerId($nestedHandler); $this->nestedHandlers[] = $nestedHandlerId; $references[] = new Reference($nestedHandlerId); } $definition->setArguments(array( $references, $handler['bubble'], )); break; case 'syslog': $definition->setArguments(array( $handler['ident'], $handler['facility'], $handler['level'], $handler['bubble'], )); break; case 'swift_mailer': if (isset($handler['email_prototype'])) { if (!empty($handler['email_prototype']['method'])) { $prototype = array(new Reference($handler['email_prototype']['id']), $handler['email_prototype']['method']); } else { $prototype = new Reference($handler['email_prototype']['id']); } } else { $message = new Definition('Swift_Message'); $message->setFactoryService('mailer'); $message->setFactoryMethod('createMessage'); $message->setPublic(false); $message->addMethodCall('setFrom', array($handler['from_email'])); $message->addMethodCall('setTo', array($handler['to_email'])); $message->addMethodCall('setSubject', array($handler['subject'])); $messageId = sprintf('%s.mail_prototype', $handlerId); $container->setDefinition($messageId, $message); $prototype = new Reference($messageId); } $definition->setArguments(array( new Reference('mailer'), $prototype, $handler['level'], $handler['bubble'], )); break; case 'native_mailer': $definition->setArguments(array( $handler['to_email'], $handler['subject'], $handler['from_email'], $handler['level'], $handler['bubble'], )); break; // Handlers using the constructor of AbstractHandler without adding their own arguments case 'test': case 'null': case 'debug': $definition->setArguments(array( $handler['level'], $handler['bubble'], )); break; default: throw new \InvalidArgumentException(sprintf('Invalid handler type "%s" given for handler "%s"', $handler['type'], $name)); } if (!empty($handler['formatter'])) { $definition->addMethodCall('setFormatter', array(new Reference($handler['formatter']))); } $container->setDefinition($handlerId, $definition); return $handlerId; } private function getHandlerId($name) { return sprintf('monolog.handler.%s', $name); } }