MonologExtension.php 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Bundle\MonologBundle\DependencyInjection;
  11. use Symfony\Component\HttpKernel\DependencyInjection\Extension;
  12. use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
  13. use Symfony\Component\DependencyInjection\ContainerBuilder;
  14. use Symfony\Component\Config\FileLocator;
  15. use Symfony\Component\Config\Definition\Processor;
  16. use Symfony\Component\DependencyInjection\Definition;
  17. use Symfony\Component\DependencyInjection\Reference;
  18. use Symfony\Component\DependencyInjection\Parameter;
  19. /**
  20. * MonologExtension is an extension for the Monolog library.
  21. *
  22. * @author Jordi Boggiano <j.boggiano@seld.be>
  23. * @author Christophe Coevoet <stof@notk.org>
  24. */
  25. class MonologExtension extends Extension
  26. {
  27. private $nestedHandlers = array();
  28. /**
  29. * Loads the Monolog configuration.
  30. *
  31. * @param array $config An array of configuration settings
  32. * @param ContainerBuilder $container A ContainerBuilder instance
  33. */
  34. public function load(array $configs, ContainerBuilder $container)
  35. {
  36. $configuration = new Configuration();
  37. $processor = new Processor();
  38. $config = $processor->processConfiguration($configuration, $configs);
  39. if (isset($config['handlers'])) {
  40. $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
  41. $loader->load('monolog.xml');
  42. $container->setAlias('logger', 'monolog.logger');
  43. $logger = $container->getDefinition('monolog.logger_prototype');
  44. if (!empty($config['processors'])) {
  45. $this->addProcessors($logger, $config['processors']);
  46. }
  47. $handlers = array();
  48. foreach ($config['handlers'] as $name => $handler) {
  49. $handlers[] = array('id' => $this->buildHandler($container, $name, $handler), 'priority' => $handler['priority'] );
  50. }
  51. $handlers = array_reverse($handlers);
  52. uasort($handlers, function($a, $b) {
  53. if ($a['priority'] == $b['priority']) {
  54. return 0;
  55. }
  56. return $a['priority'] < $b['priority'] ? -1 : 1;
  57. });
  58. foreach ($handlers as $handler) {
  59. if (!in_array($handler['id'], $this->nestedHandlers)) {
  60. $logger->addMethodCall('pushHandler', array(new Reference($handler['id'])));
  61. }
  62. }
  63. $this->addClassesToCompile(array(
  64. 'Monolog\\Formatter\\FormatterInterface',
  65. 'Monolog\\Formatter\\LineFormatter',
  66. 'Monolog\\Handler\\HandlerInterface',
  67. 'Monolog\\Handler\\AbstractHandler',
  68. 'Monolog\\Handler\\AbstractProcessingHandler',
  69. 'Monolog\\Handler\\StreamHandler',
  70. 'Monolog\\Handler\\FingersCrossedHandler',
  71. 'Monolog\\Logger',
  72. 'Symfony\\Bridge\\Monolog\\Logger',
  73. 'Symfony\\Bridge\\Monolog\\Handler\\DebugHandler',
  74. ));
  75. }
  76. }
  77. /**
  78. * Returns the base path for the XSD files.
  79. *
  80. * @return string The XSD base path
  81. */
  82. public function getXsdValidationBasePath()
  83. {
  84. return __DIR__.'/../Resources/config/schema';
  85. }
  86. public function getNamespace()
  87. {
  88. return 'http://symfony.com/schema/dic/monolog';
  89. }
  90. private function buildHandler(ContainerBuilder $container, $name, array $handler)
  91. {
  92. $handlerId = $this->getHandlerId($name);
  93. $definition = new Definition(sprintf('%%monolog.handler.%s.class%%', $handler['type']));
  94. $handler['level'] = is_int($handler['level']) ? $handler['level'] : constant('Monolog\Logger::'.strtoupper($handler['level']));
  95. switch ($handler['type']) {
  96. case 'service':
  97. $container->setAlias($handlerId, $handler['id']);
  98. return $handlerId;
  99. case 'stream':
  100. $definition->setArguments(array(
  101. $handler['path'],
  102. $handler['level'],
  103. $handler['bubble'],
  104. ));
  105. break;
  106. case 'firephp':
  107. $definition->setArguments(array(
  108. $handler['level'],
  109. $handler['bubble'],
  110. ));
  111. $definition->addTag('kernel.event_listener', array('event' => 'core.response', 'method' => 'onCoreResponse'));
  112. break;
  113. case 'rotating_file':
  114. $definition->setArguments(array(
  115. $handler['path'],
  116. $handler['max_files'],
  117. $handler['level'],
  118. $handler['bubble'],
  119. ));
  120. break;
  121. case 'fingers_crossed':
  122. $handler['action_level'] = is_int($handler['action_level']) ? $handler['action_level'] : constant('Monolog\Logger::'.strtoupper($handler['action_level']));
  123. $nestedHandlerId = $this->getHandlerId($handler['handler']);
  124. $this->nestedHandlers[] = $nestedHandlerId;
  125. $definition->setArguments(array(
  126. new Reference($nestedHandlerId),
  127. $handler['action_level'],
  128. $handler['buffer_size'],
  129. $handler['bubble'],
  130. $handler['stop_buffering'],
  131. ));
  132. break;
  133. case 'buffer':
  134. $nestedHandlerId = $this->getHandlerId($handler['handler']);
  135. $this->nestedHandlers[] = $nestedHandlerId;
  136. $definition->setArguments(array(
  137. new Reference($nestedHandlerId),
  138. $handler['buffer_size'],
  139. $handler['level'],
  140. $handler['bubble'],
  141. ));
  142. break;
  143. case 'group':
  144. $references = array();
  145. foreach ($handler['members'] as $nestedHandler) {
  146. $nestedHandlerId = $this->getHandlerId($nestedHandler);
  147. $this->nestedHandlers[] = $nestedHandlerId;
  148. $references[] = new Reference($nestedHandlerId);
  149. }
  150. $definition->setArguments(array(
  151. $references,
  152. $handler['bubble'],
  153. ));
  154. break;
  155. case 'syslog':
  156. $definition->setArguments(array(
  157. $handler['ident'],
  158. $handler['facility'],
  159. $handler['level'],
  160. $handler['bubble'],
  161. ));
  162. break;
  163. case 'swift_mailer':
  164. if (isset($handler['email_prototype'])) {
  165. $prototype = $this->parseDefinition($handler['email_prototype']);
  166. } else {
  167. $message = new Definition('Swift_Message');
  168. $message->setFactoryService('mailer');
  169. $message->setFactoryMethod('createMessage');
  170. $message->setPublic(false);
  171. $message->addMethodCall('setFrom', array($handler['from_email']));
  172. $message->addMethodCall('setTo', array($handler['to_email']));
  173. $message->addMethodCall('setSubject', array($handler['subject']));
  174. $messageId = sprintf('%s.mail_prototype', $handlerId);
  175. $container->setDefinition($messageId, $message);
  176. $prototype = new Reference($messageId);
  177. }
  178. $definition->setArguments(array(
  179. new Reference('mailer'),
  180. $prototype,
  181. $handler['level'],
  182. $handler['bubble'],
  183. ));
  184. break;
  185. case 'native_mailer':
  186. $definition->setArguments(array(
  187. $handler['to_email'],
  188. $handler['subject'],
  189. $handler['from_email'],
  190. $handler['level'],
  191. $handler['bubble'],
  192. ));
  193. break;
  194. // Handlers using the constructor of AbstractHandler without adding their own arguments
  195. case 'test':
  196. case 'null':
  197. case 'debug':
  198. $definition->setArguments(array(
  199. $handler['level'],
  200. $handler['bubble'],
  201. ));
  202. break;
  203. default:
  204. throw new \InvalidArgumentException(sprintf('Invalid handler type "%s" given for handler "%s"', $handler['type'], $name));
  205. }
  206. if (!empty($handler['formatter'])) {
  207. $definition->addMethodCall('setFormatter', array(new Reference($handler['formatter'])));
  208. }
  209. if (!empty($handler['processors'])) {
  210. $this->addProcessors($definition, $handler['processors']);
  211. }
  212. $container->setDefinition($handlerId, $definition);
  213. return $handlerId;
  214. }
  215. private function getHandlerId($name)
  216. {
  217. return sprintf('monolog.handler.%s', $name);
  218. }
  219. private function addProcessors(Definition $definition, array $processors)
  220. {
  221. foreach (array_reverse($processors) as $processor) {
  222. $definition->addMethodCall('pushProcessor', array($this->parseDefinition($processor)));
  223. }
  224. }
  225. private function parseDefinition($definition)
  226. {
  227. if (0 === strpos($definition, '@')) {
  228. return new Reference(substr($definition, 1));
  229. }
  230. return $definition;
  231. }
  232. }