vendor/symfony/monolog-bundle/DependencyInjection/MonologExtension.php line 162

Open in your IDE?
  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 Monolog\Attribute\AsMonologProcessor;
  12. use Monolog\Attribute\WithMonologChannel;
  13. use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy;
  14. use Monolog\Handler\HandlerInterface;
  15. use Monolog\Logger;
  16. use Monolog\Processor\ProcessorInterface;
  17. use Monolog\Processor\PsrLogMessageProcessor;
  18. use Monolog\ResettableInterface;
  19. use Symfony\Bridge\Monolog\Handler\FingersCrossed\HttpCodeActivationStrategy;
  20. use Symfony\Bridge\Monolog\Processor\SwitchUserTokenProcessor;
  21. use Symfony\Bridge\Monolog\Processor\TokenProcessor;
  22. use Symfony\Bridge\Monolog\Processor\WebProcessor;
  23. use Symfony\Bridge\Monolog\Logger as LegacyLogger;
  24. use Symfony\Bundle\FullStack;
  25. use Symfony\Component\Config\FileLocator;
  26. use Symfony\Component\DependencyInjection\Argument\BoundArgument;
  27. use Symfony\Component\DependencyInjection\ChildDefinition;
  28. use Symfony\Component\DependencyInjection\ContainerBuilder;
  29. use Symfony\Component\DependencyInjection\Definition;
  30. use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
  31. use Symfony\Component\DependencyInjection\Reference;
  32. use Symfony\Component\HttpKernel\DependencyInjection\Extension;
  33. use Symfony\Component\HttpKernel\Log\DebugLoggerConfigurator;
  34. use Symfony\Contracts\HttpClient\HttpClientInterface;
  35. /**
  36.  * MonologExtension is an extension for the Monolog library.
  37.  *
  38.  * @author Jordi Boggiano <j.boggiano@seld.be>
  39.  * @author Christophe Coevoet <stof@notk.org>
  40.  *
  41.  * @finalsince 3.9.0
  42.  */
  43. class MonologExtension extends Extension
  44. {
  45.     private $nestedHandlers = [];
  46.     private $swiftMailerHandlers = [];
  47.     /**
  48.      * Loads the Monolog configuration.
  49.      *
  50.      * @param array            $configs   An array of configuration settings
  51.      * @param ContainerBuilder $container A ContainerBuilder instance
  52.      */
  53.     public function load(array $configsContainerBuilder $container)
  54.     {
  55.         $configuration $this->getConfiguration($configs$container);
  56.         $config $this->processConfiguration($configuration$configs);
  57.         if (isset($config['handlers'])) {
  58.             $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
  59.             $loader->load('monolog.xml');
  60.             if (!class_exists(DebugLoggerConfigurator::class)) {
  61.                 $container->getDefinition('monolog.logger_prototype')->setClass(LegacyLogger::class);
  62.             }
  63.             $container->setParameter('monolog.use_microseconds'$config['use_microseconds']);
  64.             $handlers = [];
  65.             foreach ($config['handlers'] as $name => $handler) {
  66.                 $handlers[$handler['priority']][] = [
  67.                     'id' => $this->buildHandler($container$name$handler),
  68.                     'channels' => empty($handler['channels']) ? null $handler['channels'],
  69.                 ];
  70.             }
  71.             $container->setParameter(
  72.                 'monolog.swift_mailer.handlers',
  73.                 $this->swiftMailerHandlers
  74.             );
  75.             ksort($handlers);
  76.             $sortedHandlers = [];
  77.             foreach ($handlers as $priorityHandlers) {
  78.                 foreach (array_reverse($priorityHandlers) as $handler) {
  79.                     $sortedHandlers[] = $handler;
  80.                 }
  81.             }
  82.             $handlersToChannels = [];
  83.             foreach ($sortedHandlers as $handler) {
  84.                 if (!in_array($handler['id'], $this->nestedHandlers)) {
  85.                     $handlersToChannels[$handler['id']] = $handler['channels'];
  86.                 }
  87.             }
  88.             $container->setParameter('monolog.handlers_to_channels'$handlersToChannels);
  89.         }
  90.         $container->setParameter('monolog.additional_channels', isset($config['channels']) ? $config['channels'] : []);
  91.         if (interface_exists(ProcessorInterface::class)) {
  92.             $container->registerForAutoconfiguration(ProcessorInterface::class)
  93.                 ->addTag('monolog.processor');
  94.         } else {
  95.             $container->registerForAutoconfiguration(WebProcessor::class)
  96.                 ->addTag('monolog.processor');
  97.         }
  98.         if (interface_exists(ResettableInterface::class)) {
  99.             $container->registerForAutoconfiguration(ResettableInterface::class)
  100.                 ->addTag('kernel.reset', ['method' => 'reset']);
  101.         }
  102.         $container->registerForAutoconfiguration(TokenProcessor::class)
  103.             ->addTag('monolog.processor');
  104.         if (interface_exists(HttpClientInterface::class)) {
  105.             $handlerAutoconfiguration $container->registerForAutoconfiguration(HandlerInterface::class);
  106.             $handlerAutoconfiguration->setBindings($handlerAutoconfiguration->getBindings() + [
  107.                 HttpClientInterface::class => new BoundArgument(new Reference('monolog.http_client'), false),
  108.             ]);
  109.         }
  110.         if (80000 <= \PHP_VERSION_ID) {
  111.             $container->registerAttributeForAutoconfiguration(AsMonologProcessor::class, static function (ChildDefinition $definitionAsMonologProcessor $attribute, \Reflector $reflector): void {
  112.                 $tagAttributes get_object_vars($attribute);
  113.                 if ($reflector instanceof \ReflectionMethod) {
  114.                     if (isset($tagAttributes['method'])) {
  115.                         throw new \LogicException(sprintf('AsMonologProcessor attribute cannot declare a method on "%s::%s()".'$reflector->class$reflector->name));
  116.                     }
  117.                     $tagAttributes['method'] = $reflector->getName();
  118.                 }
  119.                 $definition->addTag('monolog.processor'$tagAttributes);
  120.             });
  121.             $container->registerAttributeForAutoconfiguration(WithMonologChannel::class, static function (ChildDefinition $definitionWithMonologChannel $attribute): void {
  122.                 $definition->addTag('monolog.logger', ['channel' => $attribute->channel]);
  123.             });
  124.         }
  125.     }
  126.     /**
  127.      * Returns the base path for the XSD files.
  128.      *
  129.      * @return string The XSD base path
  130.      */
  131.     public function getXsdValidationBasePath()
  132.     {
  133.         return __DIR__.'/../Resources/config/schema';
  134.     }
  135.     public function getNamespace()
  136.     {
  137.         return 'http://symfony.com/schema/dic/monolog';
  138.     }
  139.     private function buildHandler(ContainerBuilder $container$name, array $handler)
  140.     {
  141.         $handlerId $this->getHandlerId($name);
  142.         if ('service' === $handler['type']) {
  143.             $container->setAlias($handlerId$handler['id']);
  144.             if (!empty($handler['nested']) && true === $handler['nested']) {
  145.                 $this->markNestedHandler($handlerId);
  146.             }
  147.             return $handlerId;
  148.         }
  149.         $handlerClass $this->getHandlerClassByType($handler['type']);
  150.         $definition = new Definition($handlerClass);
  151.         if ($handler['include_stacktraces']) {
  152.             $definition->setConfigurator(['Symfony\\Bundle\\MonologBundle\\MonologBundle''includeStacktraces']);
  153.         }
  154.         if (null === $handler['process_psr_3_messages']['enabled']) {
  155.             $handler['process_psr_3_messages']['enabled'] = !isset($handler['handler']) && !$handler['members'];
  156.         }
  157.         if ($handler['process_psr_3_messages']['enabled'] && method_exists($handlerClass'pushProcessor')) {
  158.             $processorId $this->buildPsrLogMessageProcessor($container$handler['process_psr_3_messages']);
  159.             $definition->addMethodCall('pushProcessor', [new Reference($processorId)]);
  160.         }
  161.         switch ($handler['type']) {
  162.         case 'stream':
  163.             $definition->setArguments([
  164.                 $handler['path'],
  165.                 $handler['level'],
  166.                 $handler['bubble'],
  167.                 $handler['file_permission'],
  168.                 $handler['use_locking'],
  169.             ]);
  170.             break;
  171.         case 'console':
  172.             $definition->setArguments([
  173.                 null,
  174.                 $handler['bubble'],
  175.                 isset($handler['verbosity_levels']) ? $handler['verbosity_levels'] : [],
  176.                 $handler['console_formatter_options']
  177.             ]);
  178.             $definition->addTag('kernel.event_subscriber');
  179.             break;
  180.         case 'chromephp':
  181.         case 'firephp':
  182.             $definition->setArguments([
  183.                 $handler['level'],
  184.                 $handler['bubble'],
  185.             ]);
  186.             $definition->addTag('kernel.event_listener', ['event' => 'kernel.response''method' => 'onKernelResponse']);
  187.             break;
  188.         case 'gelf':
  189.             if (isset($handler['publisher']['id'])) {
  190.                 $publisher = new Reference($handler['publisher']['id']);
  191.             } elseif (class_exists('Gelf\Transport\UdpTransport')) {
  192.                 $transport = new Definition("Gelf\Transport\UdpTransport", [
  193.                     $handler['publisher']['hostname'],
  194.                     $handler['publisher']['port'],
  195.                     $handler['publisher']['chunk_size'],
  196.                 ]);
  197.                 $transport->setPublic(false);
  198.                 $publisher = new Definition('Gelf\Publisher', []);
  199.                 $publisher->addMethodCall('addTransport', [$transport]);
  200.                 $publisher->setPublic(false);
  201.             } elseif (class_exists('Gelf\MessagePublisher')) {
  202.                 $publisher = new Definition('Gelf\MessagePublisher', [
  203.                     $handler['publisher']['hostname'],
  204.                     $handler['publisher']['port'],
  205.                     $handler['publisher']['chunk_size'],
  206.                 ]);
  207.                 $publisher->setPublic(false);
  208.             } else {
  209.                 throw new \RuntimeException('The gelf handler requires the graylog2/gelf-php package to be installed');
  210.             }
  211.             $definition->setArguments([
  212.                 $publisher,
  213.                 $handler['level'],
  214.                 $handler['bubble'],
  215.             ]);
  216.             break;
  217.         case 'mongo':
  218.             if (isset($handler['mongo']['id'])) {
  219.                 $client = new Reference($handler['mongo']['id']);
  220.             } else {
  221.                 $server 'mongodb://';
  222.                 if (isset($handler['mongo']['user'])) {
  223.                     $server .= $handler['mongo']['user'].':'.$handler['mongo']['pass'].'@';
  224.                 }
  225.                 $server .= $handler['mongo']['host'].':'.$handler['mongo']['port'];
  226.                 $client = new Definition('MongoDB\Client', [
  227.                     $server,
  228.                 ]);
  229.                 $client->setPublic(false);
  230.             }
  231.             $definition->setArguments([
  232.                 $client,
  233.                 $handler['mongo']['database'],
  234.                 $handler['mongo']['collection'],
  235.                 $handler['level'],
  236.                 $handler['bubble'],
  237.             ]);
  238.             break;
  239.         case 'elasticsearch':
  240.             @trigger_error('The "elasticsearch" handler type is deprecated in MonologBundle since version 3.8.0, use the "elastica" type instead, or switch to the official Elastic client using the "elastic_search" type.'E_USER_DEPRECATED);
  241.             // no break
  242.         case 'elastica':
  243.         case 'elastic_search':
  244.             if (isset($handler['elasticsearch']['id'])) {
  245.                 $client = new Reference($handler['elasticsearch']['id']);
  246.             } else {
  247.                 if ($handler['type'] === 'elastic_search') {
  248.                     // v8 has a new Elastic\ prefix
  249.                     $client = new Definition(class_exists('Elastic\Elasticsearch\Client') ? 'Elastic\Elasticsearch\Client' 'Elasticsearch\Client');
  250.                     $factory class_exists('Elastic\Elasticsearch\ClientBuilder') ? 'Elastic\Elasticsearch\ClientBuilder' 'Elasticsearch\ClientBuilder';
  251.                     $client->setFactory([$factory'fromConfig']);
  252.                     $clientArguments = [
  253.                         'host' => $handler['elasticsearch']['host'],
  254.                     ];
  255.                     if (isset($handler['elasticsearch']['user'], $handler['elasticsearch']['password'])) {
  256.                         $clientArguments['basicAuthentication'] = [$handler['elasticsearch']['user'], $handler['elasticsearch']['password']];
  257.                     }
  258.                 } else {
  259.                     $client = new Definition('Elastica\Client');
  260.                     $clientArguments = [
  261.                         'host' => $handler['elasticsearch']['host'],
  262.                         'port' => $handler['elasticsearch']['port'],
  263.                         'transport' => $handler['elasticsearch']['transport'],
  264.                     ];
  265.                     if (isset($handler['elasticsearch']['user'], $handler['elasticsearch']['password'])) {
  266.                         $clientArguments['headers'] = [
  267.                             'Authorization' => 'Basic ' base64_encode($handler['elasticsearch']['user'] . ':' $handler['elasticsearch']['password'])
  268.                         ];
  269.                     }
  270.                 }
  271.                 $client->setArguments([
  272.                     $clientArguments
  273.                 ]);
  274.                 $client->setPublic(false);
  275.             }
  276.             // elastica handler definition
  277.             $definition->setArguments([
  278.                 $client,
  279.                 [
  280.                     'index' => $handler['index'],
  281.                     'type' => $handler['document_type'],
  282.                     'ignore_error' => $handler['ignore_error']
  283.                 ],
  284.                 $handler['level'],
  285.                 $handler['bubble'],
  286.             ]);
  287.             break;
  288.         case 'telegram':
  289.             if (!class_exists('Monolog\Handler\TelegramBotHandler')) {
  290.                 throw new \RuntimeException('The TelegramBotHandler is not available. Please update "monolog/monolog" to 2.2.0');
  291.             }
  292.             $definition->setArguments([
  293.                 $handler['token'],
  294.                 $handler['channel'],
  295.                 $handler['level'],
  296.                 $handler['bubble'],
  297.                 $handler['parse_mode'],
  298.                 $handler['disable_webpage_preview'],
  299.                 $handler['disable_notification'],
  300.                 $handler['split_long_messages'],
  301.                 $handler['delay_between_messages'],
  302.             ]);
  303.             break;
  304.         case 'redis':
  305.         case 'predis':
  306.             if (isset($handler['redis']['id'])) {
  307.                 $clientId $handler['redis']['id'];
  308.             } elseif ('redis' === $handler['type']) {
  309.                 if (!class_exists(\Redis::class)) {
  310.                     throw new \RuntimeException('The \Redis class is not available.');
  311.                 }
  312.                 $client = new Definition(\Redis::class);
  313.                 $client->addMethodCall('connect', [$handler['redis']['host'], $handler['redis']['port']]);
  314.                 $client->addMethodCall('auth', [$handler['redis']['password']]);
  315.                 $client->addMethodCall('select', [$handler['redis']['database']]);
  316.                 $client->setPublic(false);
  317.                 $clientId uniqid('monolog.redis.client.'true);
  318.                 $container->setDefinition($clientId$client);
  319.             } else {
  320.                 if (!class_exists(\Predis\Client::class)) {
  321.                     throw new \RuntimeException('The \Predis\Client class is not available.');
  322.                 }
  323.                 $client = new Definition(\Predis\Client::class);
  324.                 $client->setArguments([
  325.                     $handler['redis']['host'],
  326.                 ]);
  327.                 $client->setPublic(false);
  328.                 $clientId uniqid('monolog.predis.client.'true);
  329.                 $container->setDefinition($clientId$client);
  330.             }
  331.             $definition->setArguments([
  332.                 new Reference($clientId),
  333.                 $handler['redis']['key_name'],
  334.                 $handler['level'],
  335.                 $handler['bubble'],
  336.             ]);
  337.             break;
  338.         case 'rotating_file':
  339.             $definition->setArguments([
  340.                 $handler['path'],
  341.                 $handler['max_files'],
  342.                 $handler['level'],
  343.                 $handler['bubble'],
  344.                 $handler['file_permission'],
  345.                 $handler['use_locking'],
  346.             ]);
  347.             $definition->addMethodCall('setFilenameFormat', [
  348.                 $handler['filename_format'],
  349.                 $handler['date_format'],
  350.             ]);
  351.             break;
  352.         case 'fingers_crossed':
  353.             $nestedHandlerId $this->getHandlerId($handler['handler']);
  354.             $this->markNestedHandler($nestedHandlerId);
  355.             $activation $handler['action_level'];
  356.             if (class_exists(SwitchUserTokenProcessor::class)) {
  357.                 $activation = new Definition(ErrorLevelActivationStrategy::class, [$activation]);
  358.             }
  359.             if (isset($handler['activation_strategy'])) {
  360.                 $activation = new Reference($handler['activation_strategy']);
  361.             } elseif (!empty($handler['excluded_404s'])) {
  362.                 if (class_exists(HttpCodeActivationStrategy::class)) {
  363.                     @trigger_error('The "excluded_404s" option is deprecated in MonologBundle since version 3.4.0, you should rely on the "excluded_http_codes" option instead.'E_USER_DEPRECATED);
  364.                 }
  365.                 $activationDef = new Definition('Symfony\Bridge\Monolog\Handler\FingersCrossed\NotFoundActivationStrategy', [
  366.                     new Reference('request_stack'),
  367.                     $handler['excluded_404s'],
  368.                     $activation
  369.                 ]);
  370.                 $container->setDefinition($handlerId.'.not_found_strategy'$activationDef);
  371.                 $activation = new Reference($handlerId.'.not_found_strategy');
  372.             } elseif (!empty($handler['excluded_http_codes'])) {
  373.                 $activationDef = new Definition('Symfony\Bridge\Monolog\Handler\FingersCrossed\HttpCodeActivationStrategy', [
  374.                     new Reference('request_stack'),
  375.                     $handler['excluded_http_codes'],
  376.                     $activation
  377.                 ]);
  378.                 $container->setDefinition($handlerId.'.http_code_strategy'$activationDef);
  379.                 $activation = new Reference($handlerId.'.http_code_strategy');
  380.             }
  381.             $definition->setArguments([
  382.                 new Reference($nestedHandlerId),
  383.                 $activation,
  384.                 $handler['buffer_size'],
  385.                 $handler['bubble'],
  386.                 $handler['stop_buffering'],
  387.                 $handler['passthru_level'],
  388.             ]);
  389.             break;
  390.         case 'filter':
  391.             $nestedHandlerId $this->getHandlerId($handler['handler']);
  392.             $this->markNestedHandler($nestedHandlerId);
  393.             $minLevelOrList = !empty($handler['accepted_levels']) ? $handler['accepted_levels'] : $handler['min_level'];
  394.             $definition->setArguments([
  395.                 new Reference($nestedHandlerId),
  396.                 $minLevelOrList,
  397.                 $handler['max_level'],
  398.                 $handler['bubble'],
  399.             ]);
  400.             break;
  401.         case 'buffer':
  402.             $nestedHandlerId $this->getHandlerId($handler['handler']);
  403.             $this->markNestedHandler($nestedHandlerId);
  404.             $definition->setArguments([
  405.                 new Reference($nestedHandlerId),
  406.                 $handler['buffer_size'],
  407.                 $handler['level'],
  408.                 $handler['bubble'],
  409.                 $handler['flush_on_overflow'],
  410.             ]);
  411.             break;
  412.         case 'deduplication':
  413.             $nestedHandlerId $this->getHandlerId($handler['handler']);
  414.             $this->markNestedHandler($nestedHandlerId);
  415.             $defaultStore '%kernel.cache_dir%/monolog_dedup_'.sha1($handlerId);
  416.             $definition->setArguments([
  417.                 new Reference($nestedHandlerId),
  418.                 isset($handler['store']) ? $handler['store'] : $defaultStore,
  419.                 $handler['deduplication_level'],
  420.                 $handler['time'],
  421.                 $handler['bubble'],
  422.             ]);
  423.             break;
  424.         case 'group':
  425.         case 'whatfailuregroup':
  426.         case 'fallbackgroup':
  427.             $references = [];
  428.             foreach ($handler['members'] as $nestedHandler) {
  429.                 $nestedHandlerId $this->getHandlerId($nestedHandler);
  430.                 $this->markNestedHandler($nestedHandlerId);
  431.                 $references[] = new Reference($nestedHandlerId);
  432.             }
  433.             $definition->setArguments([
  434.                 $references,
  435.                 $handler['bubble'],
  436.             ]);
  437.             break;
  438.         case 'syslog':
  439.             $definition->setArguments([
  440.                 $handler['ident'],
  441.                 $handler['facility'],
  442.                 $handler['level'],
  443.                 $handler['bubble'],
  444.                 $handler['logopts'],
  445.             ]);
  446.             break;
  447.         case 'syslogudp':
  448.             $definition->setArguments([
  449.                 $handler['host'],
  450.                 $handler['port'],
  451.                 $handler['facility'],
  452.                 $handler['level'],
  453.                 $handler['bubble'],
  454.             ]);
  455.             if ($handler['ident']) {
  456.                 $definition->addArgument($handler['ident']);
  457.             }
  458.             break;
  459.         case 'swift_mailer':
  460.             $mailer $handler['mailer'] ?: 'mailer';
  461.             if (isset($handler['email_prototype'])) {
  462.                 if (!empty($handler['email_prototype']['method'])) {
  463.                     $prototype = [new Reference($handler['email_prototype']['id']), $handler['email_prototype']['method']];
  464.                 } else {
  465.                     $prototype = new Reference($handler['email_prototype']['id']);
  466.                 }
  467.             } else {
  468.                 $messageFactory = new Definition('Symfony\Bundle\MonologBundle\SwiftMailer\MessageFactory');
  469.                 $messageFactory->setLazy(true);
  470.                 $messageFactory->setPublic(false);
  471.                 $messageFactory->setArguments([
  472.                     new Reference($mailer),
  473.                     $handler['from_email'],
  474.                     $handler['to_email'],
  475.                     $handler['subject'],
  476.                     $handler['content_type']
  477.                 ]);
  478.                 $messageFactoryId sprintf('%s.mail_message_factory'$handlerId);
  479.                 $container->setDefinition($messageFactoryId$messageFactory);
  480.                 // set the prototype as a callable
  481.                 $prototype = [new Reference($messageFactoryId), 'createMessage'];
  482.             }
  483.             $definition->setArguments([
  484.                 new Reference($mailer),
  485.                 $prototype,
  486.                 $handler['level'],
  487.                 $handler['bubble'],
  488.             ]);
  489.             $this->swiftMailerHandlers[] = $handlerId;
  490.             $definition->addTag('kernel.event_listener', ['event' => 'kernel.terminate''method' => 'onKernelTerminate']);
  491.             $definition->addTag('kernel.event_listener', ['event' => 'console.terminate''method' => 'onCliTerminate']);
  492.             break;
  493.         case 'native_mailer':
  494.             $definition->setArguments([
  495.                 $handler['to_email'],
  496.                 $handler['subject'],
  497.                 $handler['from_email'],
  498.                 $handler['level'],
  499.                 $handler['bubble'],
  500.             ]);
  501.             if (!empty($handler['headers'])) {
  502.                 $definition->addMethodCall('addHeader', [$handler['headers']]);
  503.             }
  504.             break;
  505.         case 'symfony_mailer':
  506.             $mailer $handler['mailer'] ?: 'mailer.mailer';
  507.             if (isset($handler['email_prototype'])) {
  508.                 if (!empty($handler['email_prototype']['method'])) {
  509.                     $prototype = [new Reference($handler['email_prototype']['id']), $handler['email_prototype']['method']];
  510.                 } else {
  511.                     $prototype = new Reference($handler['email_prototype']['id']);
  512.                 }
  513.             } else {
  514.                 $prototype = (new Definition('Symfony\Component\Mime\Email'))
  515.                     ->setPublic(false)
  516.                     ->addMethodCall('from', [$handler['from_email']])
  517.                     ->addMethodCall('to'$handler['to_email'])
  518.                     ->addMethodCall('subject', [$handler['subject']]);
  519.             }
  520.             $definition->setArguments([
  521.                 new Reference($mailer),
  522.                 $prototype,
  523.                 $handler['level'],
  524.                 $handler['bubble'],
  525.             ]);
  526.             break;
  527.         case 'socket':
  528.             $definition->setArguments([
  529.                 $handler['connection_string'],
  530.                 $handler['level'],
  531.                 $handler['bubble'],
  532.             ]);
  533.             if (isset($handler['timeout'])) {
  534.                 $definition->addMethodCall('setTimeout', [$handler['timeout']]);
  535.             }
  536.             if (isset($handler['connection_timeout'])) {
  537.                 $definition->addMethodCall('setConnectionTimeout', [$handler['connection_timeout']]);
  538.             }
  539.             if (isset($handler['persistent'])) {
  540.                 $definition->addMethodCall('setPersistent', [$handler['persistent']]);
  541.             }
  542.             break;
  543.         case 'pushover':
  544.             $definition->setArguments([
  545.                 $handler['token'],
  546.                 $handler['user'],
  547.                 $handler['title'],
  548.                 $handler['level'],
  549.                 $handler['bubble'],
  550.             ]);
  551.             if (isset($handler['timeout'])) {
  552.                 $definition->addMethodCall('setTimeout', [$handler['timeout']]);
  553.             }
  554.             if (isset($handler['connection_timeout'])) {
  555.                 $definition->addMethodCall('setConnectionTimeout', [$handler['connection_timeout']]);
  556.             }
  557.             break;
  558.         case 'hipchat':
  559.             $definition->setArguments([
  560.                 $handler['token'],
  561.                 $handler['room'],
  562.                 $handler['nickname'],
  563.                 $handler['notify'],
  564.                 $handler['level'],
  565.                 $handler['bubble'],
  566.                 $handler['use_ssl'],
  567.                 $handler['message_format'],
  568.                 !empty($handler['host']) ? $handler['host'] : 'api.hipchat.com',
  569.                 !empty($handler['api_version']) ? $handler['api_version'] : 'v1',
  570.             ]);
  571.             if (isset($handler['timeout'])) {
  572.                 $definition->addMethodCall('setTimeout', [$handler['timeout']]);
  573.             }
  574.             if (isset($handler['connection_timeout'])) {
  575.                 $definition->addMethodCall('setConnectionTimeout', [$handler['connection_timeout']]);
  576.             }
  577.             break;
  578.         case 'slack':
  579.             $definition->setArguments([
  580.                 $handler['token'],
  581.                 $handler['channel'],
  582.                 $handler['bot_name'],
  583.                 $handler['use_attachment'],
  584.                 $handler['icon_emoji'],
  585.                 $handler['level'],
  586.                 $handler['bubble'],
  587.                 $handler['use_short_attachment'],
  588.                 $handler['include_extra'],
  589.             ]);
  590.             if (isset($handler['timeout'])) {
  591.                 $definition->addMethodCall('setTimeout', [$handler['timeout']]);
  592.             }
  593.             if (isset($handler['connection_timeout'])) {
  594.                 $definition->addMethodCall('setConnectionTimeout', [$handler['connection_timeout']]);
  595.             }
  596.             break;
  597.         case 'slackwebhook':
  598.             $definition->setArguments([
  599.                 $handler['webhook_url'],
  600.                 $handler['channel'],
  601.                 $handler['bot_name'],
  602.                 $handler['use_attachment'],
  603.                 $handler['icon_emoji'],
  604.                 $handler['use_short_attachment'],
  605.                 $handler['include_extra'],
  606.                 $handler['level'],
  607.                 $handler['bubble'],
  608.             ]);
  609.             break;
  610.         case 'slackbot':
  611.             $definition->setArguments([
  612.                 $handler['team'],
  613.                 $handler['token'],
  614.                 urlencode($handler['channel']),
  615.                 $handler['level'],
  616.                 $handler['bubble'],
  617.             ]);
  618.             break;
  619.         case 'cube':
  620.             $definition->setArguments([
  621.                 $handler['url'],
  622.                 $handler['level'],
  623.                 $handler['bubble'],
  624.             ]);
  625.             break;
  626.         case 'amqp':
  627.             $definition->setArguments([
  628.                 new Reference($handler['exchange']),
  629.                 $handler['exchange_name'],
  630.                 $handler['level'],
  631.                 $handler['bubble'],
  632.             ]);
  633.             break;
  634.         case 'error_log':
  635.             $definition->setArguments([
  636.                 $handler['message_type'],
  637.                 $handler['level'],
  638.                 $handler['bubble'],
  639.             ]);
  640.             break;
  641.         case 'sentry':
  642.             if (null !== $handler['hub_id']) {
  643.                 $hub = new Reference($handler['hub_id']);
  644.             } else {
  645.                 if (null !== $handler['client_id']) {
  646.                     $clientId $handler['client_id'];
  647.                 } else {
  648.                     $options = new Definition(
  649.                         'Sentry\\Options',
  650.                         [['dsn' => $handler['dsn']]]
  651.                     );
  652.                     if (!empty($handler['environment'])) {
  653.                         $options->addMethodCall('setEnvironment', [$handler['environment']]);
  654.                     }
  655.                     if (!empty($handler['release'])) {
  656.                         $options->addMethodCall('setRelease', [$handler['release']]);
  657.                     }
  658.                     $builder = new Definition('Sentry\\ClientBuilder', [$options]);
  659.                     $client = new Definition('Sentry\\Client');
  660.                     $client->setFactory([$builder'getClient']);
  661.                     $clientId 'monolog.sentry.client.'.sha1($handler['dsn']);
  662.                     $container->setDefinition($clientId$client);
  663.                     if (!$container->hasAlias('Sentry\\ClientInterface')) {
  664.                         $container->setAlias('Sentry\\ClientInterface'$clientId);
  665.                     }
  666.                 }
  667.                 $hub = new Definition(
  668.                     'Sentry\\State\\Hub',
  669.                     [new Reference($clientId)]
  670.                 );
  671.                 $container->setDefinition(sprintf('monolog.handler.%s.hub'$name), $hub);
  672.                 // can't set the hub to the current hub, getting into a recursion otherwise...
  673.                 //$hub->addMethodCall('setCurrent', array($hub));
  674.             }
  675.             $definition->setArguments([
  676.                 $hub,
  677.                 $handler['level'],
  678.                 $handler['bubble'],
  679.                 $handler['fill_extra_context'],
  680.             ]);
  681.             break;
  682.         case 'raven':
  683.             if (null !== $handler['client_id']) {
  684.                 $clientId $handler['client_id'];
  685.             } else {
  686.                 $client = new Definition('Raven_Client', [
  687.                     $handler['dsn'],
  688.                     [
  689.                         'auto_log_stacks' => $handler['auto_log_stacks'],
  690.                         'environment' => $handler['environment']
  691.                     ]
  692.                 ]);
  693.                 $client->setPublic(false);
  694.                 $clientId 'monolog.raven.client.'.sha1($handler['dsn']);
  695.                 $container->setDefinition($clientId$client);
  696.             }
  697.             $definition->setArguments([
  698.                 new Reference($clientId),
  699.                 $handler['level'],
  700.                 $handler['bubble'],
  701.             ]);
  702.             if (!empty($handler['release'])) {
  703.                 $definition->addMethodCall('setRelease', [$handler['release']]);
  704.             }
  705.             break;
  706.         case 'loggly':
  707.             $definition->setArguments([
  708.                 $handler['token'],
  709.                 $handler['level'],
  710.                 $handler['bubble'],
  711.             ]);
  712.             if (!empty($handler['tags'])) {
  713.                 $definition->addMethodCall('setTag', [implode(','$handler['tags'])]);
  714.             }
  715.             break;
  716.         case 'logentries':
  717.             $definition->setArguments([
  718.                 $handler['token'],
  719.                 $handler['use_ssl'],
  720.                 $handler['level'],
  721.                 $handler['bubble'],
  722.             ]);
  723.             if (isset($handler['timeout'])) {
  724.                 $definition->addMethodCall('setTimeout', [$handler['timeout']]);
  725.             }
  726.             if (isset($handler['connection_timeout'])) {
  727.                 $definition->addMethodCall('setConnectionTimeout', [$handler['connection_timeout']]);
  728.             }
  729.             break;
  730.         case 'insightops':
  731.             $definition->setArguments([
  732.                 $handler['token'],
  733.                 $handler['region'] ? $handler['region'] : 'us',
  734.                 $handler['use_ssl'],
  735.                 $handler['level'],
  736.                 $handler['bubble'],
  737.             ]);
  738.             break;
  739.         case 'flowdock':
  740.             $definition->setArguments([
  741.                 $handler['token'],
  742.                 $handler['level'],
  743.                 $handler['bubble'],
  744.             ]);
  745.             if (empty($handler['formatter'])) {
  746.                 $formatter = new Definition("Monolog\Formatter\FlowdockFormatter", [
  747.                     $handler['source'],
  748.                     $handler['from_email'],
  749.                 ]);
  750.                 $formatterId 'monolog.flowdock.formatter.'.sha1($handler['source'].'|'.$handler['from_email']);
  751.                 $formatter->setPublic(false);
  752.                 $container->setDefinition($formatterId$formatter);
  753.                 $definition->addMethodCall('setFormatter', [new Reference($formatterId)]);
  754.             }
  755.             break;
  756.         case 'rollbar':
  757.             if (!empty($handler['id'])) {
  758.                 $rollbarId $handler['id'];
  759.             } else {
  760.                 $config $handler['config'] ?: [];
  761.                 $config['access_token'] = $handler['token'];
  762.                 $rollbar = new Definition('RollbarNotifier', [
  763.                     $config,
  764.                 ]);
  765.                 $rollbarId 'monolog.rollbar.notifier.'.sha1(json_encode($config));
  766.                 $rollbar->setPublic(false);
  767.                 $container->setDefinition($rollbarId$rollbar);
  768.             }
  769.             $definition->setArguments([
  770.                 new Reference($rollbarId),
  771.                 $handler['level'],
  772.                 $handler['bubble'],
  773.             ]);
  774.             break;
  775.         case 'newrelic':
  776.             $definition->setArguments([
  777.                 $handler['level'],
  778.                 $handler['bubble'],
  779.                 $handler['app_name'],
  780.             ]);
  781.             break;
  782.         case 'server_log':
  783.             $definition->setArguments([
  784.                 $handler['host'],
  785.                 $handler['level'],
  786.                 $handler['bubble'],
  787.             ]);
  788.             break;
  789.         case 'sampling':
  790.             $nestedHandlerId $this->getHandlerId($handler['handler']);
  791.             $this->markNestedHandler($nestedHandlerId);
  792.             $definition->setArguments([
  793.                 new Reference($nestedHandlerId),
  794.                 $handler['factor'],
  795.             ]);
  796.             break;
  797.         // Handlers using the constructor of AbstractHandler without adding their own arguments
  798.         case 'browser_console':
  799.         case 'test':
  800.         case 'null':
  801.         case 'noop':
  802.         case 'debug':
  803.             $definition->setArguments([
  804.                 $handler['level'],
  805.                 $handler['bubble'],
  806.             ]);
  807.             break;
  808.         default:
  809.             $nullWarning '';
  810.             if ($handler['type'] == '') {
  811.                 $nullWarning ', if you meant to define a null handler in a yaml config, make sure you quote "null" so it does not get converted to a php null';
  812.             }
  813.             throw new \InvalidArgumentException(sprintf('Invalid handler type "%s" given for handler "%s"' $nullWarning$handler['type'], $name));
  814.         }
  815.         if (!empty($handler['nested']) && true === $handler['nested']) {
  816.             $this->markNestedHandler($handlerId);
  817.         }
  818.         if (!empty($handler['formatter'])) {
  819.             $definition->addMethodCall('setFormatter', [new Reference($handler['formatter'])]);
  820.         }
  821.         if (!in_array($handlerId$this->nestedHandlers) && is_subclass_of($handlerClassResettableInterface::class)) {
  822.             $definition->addTag('kernel.reset', ['method' => 'reset']);
  823.         }
  824.         $container->setDefinition($handlerId$definition);
  825.         return $handlerId;
  826.     }
  827.     private function markNestedHandler($nestedHandlerId)
  828.     {
  829.         if (in_array($nestedHandlerId$this->nestedHandlers)) {
  830.             return;
  831.         }
  832.         $this->nestedHandlers[] = $nestedHandlerId;
  833.     }
  834.     private function getHandlerId($name)
  835.     {
  836.         return sprintf('monolog.handler.%s'$name);
  837.     }
  838.     private function getHandlerClassByType($handlerType)
  839.     {
  840.         $typeToClassMapping = [
  841.             'stream' => 'Monolog\Handler\StreamHandler',
  842.             'console' => 'Symfony\Bridge\Monolog\Handler\ConsoleHandler',
  843.             'group' => 'Monolog\Handler\GroupHandler',
  844.             'buffer' => 'Monolog\Handler\BufferHandler',
  845.             'deduplication' => 'Monolog\Handler\DeduplicationHandler',
  846.             'rotating_file' => 'Monolog\Handler\RotatingFileHandler',
  847.             'syslog' => 'Monolog\Handler\SyslogHandler',
  848.             'syslogudp' => 'Monolog\Handler\SyslogUdpHandler',
  849.             'null' => 'Monolog\Handler\NullHandler',
  850.             'test' => 'Monolog\Handler\TestHandler',
  851.             'gelf' => 'Monolog\Handler\GelfHandler',
  852.             'rollbar' => 'Monolog\Handler\RollbarHandler',
  853.             'flowdock' => 'Monolog\Handler\FlowdockHandler',
  854.             'browser_console' => 'Monolog\Handler\BrowserConsoleHandler',
  855.             'firephp' => 'Symfony\Bridge\Monolog\Handler\FirePHPHandler',
  856.             'chromephp' => 'Symfony\Bridge\Monolog\Handler\ChromePhpHandler',
  857.             'debug' => 'Symfony\Bridge\Monolog\Handler\DebugHandler',
  858.             'swift_mailer' => 'Symfony\Bridge\Monolog\Handler\SwiftMailerHandler',
  859.             'native_mailer' => 'Monolog\Handler\NativeMailerHandler',
  860.             'symfony_mailer' => 'Symfony\Bridge\Monolog\Handler\MailerHandler',
  861.             'socket' => 'Monolog\Handler\SocketHandler',
  862.             'pushover' => 'Monolog\Handler\PushoverHandler',
  863.             'raven' => 'Monolog\Handler\RavenHandler',
  864.             'sentry' => 'Sentry\Monolog\Handler',
  865.             'newrelic' => 'Monolog\Handler\NewRelicHandler',
  866.             'hipchat' => 'Monolog\Handler\HipChatHandler',
  867.             'slack' => 'Monolog\Handler\SlackHandler',
  868.             'slackwebhook' => 'Monolog\Handler\SlackWebhookHandler',
  869.             'slackbot' => 'Monolog\Handler\SlackbotHandler',
  870.             'cube' => 'Monolog\Handler\CubeHandler',
  871.             'amqp' => 'Monolog\Handler\AmqpHandler',
  872.             'error_log' => 'Monolog\Handler\ErrorLogHandler',
  873.             'loggly' => 'Monolog\Handler\LogglyHandler',
  874.             'logentries' => 'Monolog\Handler\LogEntriesHandler',
  875.             'whatfailuregroup' => 'Monolog\Handler\WhatFailureGroupHandler',
  876.             'fingers_crossed' => 'Monolog\Handler\FingersCrossedHandler',
  877.             'filter' => 'Monolog\Handler\FilterHandler',
  878.             'mongo' => 'Monolog\Handler\MongoDBHandler',
  879.             'elasticsearch' => 'Monolog\Handler\ElasticSearchHandler',
  880.             'telegram' => 'Monolog\Handler\TelegramBotHandler',
  881.             'server_log' => 'Symfony\Bridge\Monolog\Handler\ServerLogHandler',
  882.             'redis' => 'Monolog\Handler\RedisHandler',
  883.             'predis' => 'Monolog\Handler\RedisHandler',
  884.             'insightops' => 'Monolog\Handler\InsightOpsHandler',
  885.             'sampling' => 'Monolog\Handler\SamplingHandler',
  886.         ];
  887.         $v2HandlerTypesAdded = [
  888.             'elastica' => 'Monolog\Handler\ElasticaHandler',
  889.             'elasticsearch' => 'Monolog\Handler\ElasticaHandler',
  890.             'elastic_search' => 'Monolog\Handler\ElasticsearchHandler',
  891.             'fallbackgroup' => 'Monolog\Handler\FallbackGroupHandler',
  892.             'noop' => 'Monolog\Handler\NoopHandler',
  893.         ];
  894.         $v2HandlerTypesRemoved = [
  895.             'hipchat',
  896.             'raven',
  897.             'slackbot',
  898.         ];
  899.         $v3HandlerTypesRemoved = [
  900.             'swift_mailer',
  901.         ];
  902.         if (Logger::API >= 2) {
  903.             $typeToClassMapping array_merge($typeToClassMapping$v2HandlerTypesAdded);
  904.             foreach($v2HandlerTypesRemoved as $v2HandlerTypeRemoved) {
  905.                 unset($typeToClassMapping[$v2HandlerTypeRemoved]);
  906.             }
  907.         }
  908.         if (Logger::API >= 3) {
  909.             foreach($v3HandlerTypesRemoved as $v3HandlerTypeRemoved) {
  910.                 unset($typeToClassMapping[$v3HandlerTypeRemoved]);
  911.             }
  912.         }
  913.         if (!isset($typeToClassMapping[$handlerType])) {
  914.             if (Logger::API === && array_key_exists($handlerType$v2HandlerTypesAdded)) {
  915.                 throw new \InvalidArgumentException(sprintf('"%s" was added in Monolog v2, please upgrade if you wish to use it.'$handlerType));
  916.             }
  917.             if (Logger::API >= && array_key_exists($handlerType$v2HandlerTypesRemoved)) {
  918.                 throw new \InvalidArgumentException(sprintf('"%s" was removed in Monolog v2.'$handlerType));
  919.             }
  920.             if (Logger::API >= && array_key_exists($handlerType$v3HandlerTypesRemoved)) {
  921.                 throw new \InvalidArgumentException(sprintf('"%s" was removed in Monolog v3.'$handlerType));
  922.             }
  923.             throw new \InvalidArgumentException(sprintf('There is no handler class defined for handler "%s".'$handlerType));
  924.         }
  925.         return $typeToClassMapping[$handlerType];
  926.     }
  927.     private function buildPsrLogMessageProcessor(ContainerBuilder $container, array $processorOptions): string
  928.     {
  929.         static $hasConstructorArguments;
  930.         if (!isset($hasConstructorArguments)) {
  931.             $reflectionConstructor = (new \ReflectionClass(PsrLogMessageProcessor::class))->getConstructor();
  932.             $hasConstructorArguments null !== $reflectionConstructor && $reflectionConstructor->getNumberOfParameters() > 0;
  933.             unset($reflectionConstructor);
  934.         }
  935.         $processorId 'monolog.processor.psr_log_message';
  936.         $processorArguments = [];
  937.         unset($processorOptions['enabled']);
  938.         if (!empty($processorOptions)) {
  939.             if (!$hasConstructorArguments) {
  940.                 throw new \RuntimeException('Monolog 1.26 or higher is required for the "date_format" and "remove_used_context_fields" options to be used.');
  941.             }
  942.             $processorArguments = [
  943.                 $processorOptions['date_format'] ?? null,
  944.                 $processorOptions['remove_used_context_fields'] ?? false,
  945.             ];
  946.             $processorId .= '.'.ContainerBuilder::hash($processorArguments);
  947.         }
  948.         if (!$container->hasDefinition($processorId)) {
  949.             $processor = new Definition(PsrLogMessageProcessor::class);
  950.             $processor->setPublic(false);
  951.             $processor->setArguments($processorArguments);
  952.             $container->setDefinition($processorId$processor);
  953.         }
  954.         return $processorId;
  955.     }
  956. }