Initial commit with Symfony 2.1+Vendors

Signed-off-by: Gergely POLONKAI (W00d5t0ck) <polesz@w00d5t0ck.info>
This commit is contained in:
Polonkai Gergely
2012-07-01 09:52:20 +02:00
commit 082a0130c2
5381 changed files with 416709 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
language: php
php:
- 5.3
- 5.4
before_script:
- curl -s http://getcomposer.org/installer | php
- php composer.phar install --dev

View File

@@ -0,0 +1,59 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\MonologBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Reference;
/**
* Registers processors in Monolog loggers or handlers.
*
* @author Christophe Coevoet <stof@notk.org>
*/
class AddProcessorsPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('monolog.logger')) {
return;
}
foreach ($container->findTaggedServiceIds('monolog.processor') as $id => $tags) {
foreach ($tags as $tag) {
if (!empty($tag['channel']) && !empty($tag['handler'])) {
throw new \InvalidArgumentException(sprintf('you cannot specify both the "handler" and "channel" attributes for the "monolog.processor" tag on service "%s"', $id));
}
if (!empty($tag['handler'])) {
$definition = $container->findDefinition(sprintf('monolog.handler.%s', $tag['handler']));
} elseif (!empty($tag['channel'])) {
if ('app' === $tag['channel']) {
$definition = $container->getDefinition('monolog.logger');
} else {
$definition = $container->getDefinition(sprintf('monolog.logger.%s', $tag['channel']));
}
} else {
$definition = $container->getDefinition('monolog.logger_prototype');
}
if (!empty($tag['method'])) {
$processor = array(new Reference($id), $tag['method']);
} else {
// If no method is defined, fallback to use __invoke
$processor = new Reference($id);
}
$definition->addMethodCall('pushProcessor', array($processor));
}
}
}
}

View File

@@ -0,0 +1,49 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\MonologBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Definition;
use Monolog\Logger;
/**
* Adds the DebugHandler when the profiler is enabled.
*
* @author Christophe Coevoet <stof@notk.org>
*/
class DebugHandlerPass implements CompilerPassInterface
{
private $channelPass;
public function __construct(LoggerChannelPass $channelPass)
{
$this->channelPass = $channelPass;
}
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('profiler')) {
return;
}
$debugHandler = new Definition('%monolog.handler.debug.class%', array(Logger::DEBUG, true));
$container->setDefinition('monolog.handler.debug', $debugHandler);
foreach ($this->channelPass->getChannels() as $channel) {
$container
->getDefinition($channel === 'app' ? 'monolog.logger' : 'monolog.logger.'.$channel)
->addMethodCall('pushHandler', array(new Reference('monolog.handler.debug')));
}
}
}

View File

@@ -0,0 +1,105 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\MonologBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
/**
* Replaces the default logger by another one with its own channel for tagged services.
*
* @author Christophe Coevoet <stof@notk.org>
*/
class LoggerChannelPass implements CompilerPassInterface
{
protected $channels = array('app');
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('monolog.logger')) {
return;
}
foreach ($container->findTaggedServiceIds('monolog.logger') as $id => $tags) {
foreach ($tags as $tag) {
if (empty($tag['channel']) || 'app' === $tag['channel']) {
continue;
}
$definition = $container->getDefinition($id);
$loggerId = sprintf('monolog.logger.%s', $tag['channel']);
$this->createLogger($tag['channel'], $loggerId, $container);
foreach ($definition->getArguments() as $index => $argument) {
if ($argument instanceof Reference && 'logger' === (string) $argument) {
$definition->replaceArgument($index, new Reference($loggerId, $argument->getInvalidBehavior(), $argument->isStrict()));
}
}
$calls = $definition->getMethodCalls();
foreach ($calls as $i => $call) {
foreach ($call[1] as $index => $argument) {
if ($argument instanceof Reference && 'logger' === (string) $argument) {
$calls[$i][1][$index] = new Reference($loggerId, $argument->getInvalidBehavior(), $argument->isStrict());
}
}
}
$definition->setMethodCalls($calls);
}
}
$handlersToChannels = $container->getParameter('monolog.handlers_to_channels');
foreach ($handlersToChannels as $handler => $channels) {
foreach ($this->processChannels($channels) as $channel) {
try {
$logger = $container->getDefinition($channel === 'app' ? 'monolog.logger' : 'monolog.logger.'.$channel);
} catch (InvalidArgumentException $e) {
$msg = 'Monolog configuration error: The logging channel "'.$channel.'" assigned to the "'.substr($handler, 16).'" handler does not exist.';
throw new \InvalidArgumentException($msg, 0, $e);
}
$logger->addMethodCall('pushHandler', array(new Reference($handler)));
}
}
}
public function getChannels()
{
return $this->channels;
}
protected function processChannels($configuration)
{
if (null === $configuration) {
return $this->channels;
}
if ('inclusive' === $configuration['type']) {
return $configuration['elements'];
}
return array_diff($this->channels, $configuration['elements']);
}
protected function createLogger($channel, $loggerId, ContainerBuilder $container)
{
if (!in_array($channel, $this->channels)) {
$logger = new DefinitionDecorator('monolog.logger_prototype');
$logger->replaceArgument(0, $channel);
$container->setDefinition($loggerId, $logger);
$this->channels[] = $channel;
}
}
}

View File

@@ -0,0 +1,215 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
/**
* This class contains the configuration information for the bundle
*
* This information is solely responsible for how the different configuration
* sections are normalized, and merged.
*
* @author Jordi Boggiano <j.boggiano@seld.be>
* @author Christophe Coevoet <stof@notk.org>
*/
class Configuration implements ConfigurationInterface
{
/**
* Generates the configuration tree builder.
*
* @return \Symfony\Component\Config\Definition\Builder\TreeBuilder The tree builder
*/
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('monolog');
$rootNode
->fixXmlConfig('handler')
->children()
->arrayNode('handlers')
->canBeUnset()
->useAttributeAsKey('name')
->prototype('array')
->fixXmlConfig('member')
->canBeUnset()
->children()
->scalarNode('type')
->isRequired()
->treatNullLike('null')
->beforeNormalization()
->always()
->then(function($v) { return strtolower($v); })
->end()
->end()
->scalarNode('id')->end()
->scalarNode('priority')->defaultValue(0)->end()
->scalarNode('level')->defaultValue('DEBUG')->end()
->booleanNode('bubble')->defaultTrue()->end()
->scalarNode('path')->defaultValue('%kernel.logs_dir%/%kernel.environment%.log')->end() // stream and rotating
->scalarNode('ident')->defaultFalse()->end() // syslog
->scalarNode('facility')->defaultValue('user')->end() // syslog
->scalarNode('max_files')->defaultValue(0)->end() // rotating
->scalarNode('action_level')->defaultValue('WARNING')->end() // fingers_crossed
->scalarNode('activation_strategy')->defaultNull()->end() // fingers_crossed
->booleanNode('stop_buffering')->defaultTrue()->end()// fingers_crossed
->scalarNode('buffer_size')->defaultValue(0)->end() // fingers_crossed and buffer
->scalarNode('handler')->end() // fingers_crossed and buffer
->arrayNode('publisher')
->canBeUnset()
->beforeNormalization()
->ifString()
->then(function($v) { return array('id'=> $v); })
->end()
->children()
->scalarNode('id')->end()
->scalarNode('hostname')->end()
->scalarNode('port')->defaultValue(12201)->end()
->scalarNode('chunk_size')->defaultValue(1420)->end()
->end()
->validate()
->ifTrue(function($v) {
return !isset($v['id']) && !isset($v['hostname']);
})
->thenInvalid('What must be set is either the hostname or the id.')
->end()
->end() // gelf
->arrayNode('members') // group
->canBeUnset()
->performNoDeepMerging()
->prototype('scalar')->end()
->end()
->scalarNode('from_email')->end() // swift_mailer and native_mailer
->scalarNode('to_email')->end() // swift_mailer and native_mailer
->scalarNode('subject')->end() // swift_mailer and native_mailer
->arrayNode('email_prototype') // swift_mailer
->canBeUnset()
->beforeNormalization()
->ifString()
->then(function($v) { return array('id' => $v); })
->end()
->children()
->scalarNode('id')->isRequired()->end()
->scalarNode('factory-method')->defaultNull()->end()
->end()
->end()
->arrayNode('channels')
->fixXmlConfig('channel', 'elements')
->canBeUnset()
->beforeNormalization()
->ifString()
->then(function($v) { return array('elements' => array($v)); })
->end()
->beforeNormalization()
->ifTrue(function($v) { return is_array($v) && is_numeric(key($v)); })
->then(function($v) { return array('elements' => $v); })
->end()
->validate()
->ifTrue(function($v) { return empty($v); })
->thenUnset()
->end()
->validate()
->always(function ($v) {
$isExclusive = null;
if (isset($v['type'])) {
$isExclusive = 'exclusive' === $v['type'];
}
$elements = array();
foreach ($v['elements'] as $element) {
if (0 === strpos($element, '!')) {
if (false === $isExclusive) {
throw new InvalidConfigurationException('Cannot combine exclusive/inclusive definitions in channels list.');
}
$elements[] = substr($element, 1);
$isExclusive = true;
} else {
if (true === $isExclusive) {
throw new InvalidConfigurationException('Cannot combine exclusive/inclusive definitions in channels list');
}
$elements[] = $element;
$isExclusive = false;
}
}
return array('type' => $isExclusive ? 'exclusive' : 'inclusive', 'elements' => $elements);
})
->end()
->children()
->scalarNode('type')
->validate()
->ifNotInArray(array('inclusive', 'exclusive'))
->thenInvalid('The type of channels has to be inclusive or exclusive')
->end()
->end()
->arrayNode('elements')
->prototype('scalar')->end()
->end()
->end()
->end()
->scalarNode('formatter')->end()
->end()
->validate()
->ifTrue(function($v) { return ('fingers_crossed' === $v['type'] || 'buffer' === $v['type']) && 1 !== count($v['handler']); })
->thenInvalid('The handler has to be specified to use a FingersCrossedHandler or BufferHandler')
->end()
->validate()
->ifTrue(function($v) { return 'swift_mailer' === $v['type'] && empty($v['email_prototype']) && (empty($v['from_email']) || empty($v['to_email']) || empty($v['subject'])); })
->thenInvalid('The sender, recipient and subject or an email prototype have to be specified to use a SwiftMailerHandler')
->end()
->validate()
->ifTrue(function($v) { return 'native_mailer' === $v['type'] && (empty($v['from_email']) || empty($v['to_email']) || empty($v['subject'])); })
->thenInvalid('The sender, recipient and subject have to be specified to use a NativeMailerHandler')
->end()
->validate()
->ifTrue(function($v) { return 'service' === $v['type'] && !isset($v['id']); })
->thenInvalid('The id has to be specified to use a service as handler')
->end()
->validate()
->ifTrue(function($v) { return 'gelf' === $v['type'] && !isset($v['publisher']); })
->thenInvalid('The publisher has to be specified to use a GelfHandler')
->end()
->end()
->validate()
->ifTrue(function($v) { return isset($v['debug']); })
->thenInvalid('The "debug" name cannot be used as it is reserved for the handler of the profiler')
->end()
->example(array(
'syslog' => array(
'type' => 'stream',
'path' => '/var/log/symfony.log',
'level' => 'ERROR',
'bubble' => 'false',
'formatter' => 'my_formatter',
'processors' => array('some_callable')
),
'main' => array(
'type' => 'fingers_crossed',
'action_level' => 'WARNING',
'buffer_size' => 30,
'handler' => 'custom',
),
'custom' => array(
'type' => 'service',
'id' => 'my_handler'
)
))
->end()
->end()
;
return $treeBuilder;
}
}

View File

@@ -0,0 +1,289 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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 <j.boggiano@seld.be>
* @author Christophe Coevoet <stof@notk.org>
*/
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);
}
}

View File

@@ -0,0 +1,19 @@
Copyright (c) 2004-2012 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,35 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\MonologBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Bundle\MonologBundle\DependencyInjection\Compiler\LoggerChannelPass;
use Symfony\Bundle\MonologBundle\DependencyInjection\Compiler\DebugHandlerPass;
use Symfony\Bundle\MonologBundle\DependencyInjection\Compiler\AddProcessorsPass;
/**
* Bundle.
*
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class MonologBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
parent::build($container);
$container->addCompilerPass($channelPass = new LoggerChannelPass());
$container->addCompilerPass(new DebugHandlerPass($channelPass));
$container->addCompilerPass(new AddProcessorsPass());
}
}

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="monolog.logger.class">Symfony\Bridge\Monolog\Logger</parameter>
<parameter key="monolog.gelf.publisher.class">Gelf\MessagePublisher</parameter>
<parameter key="monolog.handler.stream.class">Monolog\Handler\StreamHandler</parameter>
<parameter key="monolog.handler.group.class">Monolog\Handler\GroupHandler</parameter>
<parameter key="monolog.handler.buffer.class">Monolog\Handler\BufferHandler</parameter>
<parameter key="monolog.handler.rotating_file.class">Monolog\Handler\RotatingFileHandler</parameter>
<parameter key="monolog.handler.syslog.class">Monolog\Handler\SyslogHandler</parameter>
<parameter key="monolog.handler.null.class">Monolog\Handler\NullHandler</parameter>
<parameter key="monolog.handler.test.class">Monolog\Handler\TestHandler</parameter>
<parameter key="monolog.handler.gelf.class">Monolog\Handler\GelfHandler</parameter>
<parameter key="monolog.handler.firephp.class">Symfony\Bridge\Monolog\Handler\FirePHPHandler</parameter>
<parameter key="monolog.handler.chromephp.class">Symfony\Bridge\Monolog\Handler\ChromePhpHandler</parameter>
<parameter key="monolog.handler.debug.class">Symfony\Bridge\Monolog\Handler\DebugHandler</parameter>
<parameter key="monolog.handler.swift_mailer.class">Monolog\Handler\SwiftMailerHandler</parameter>
<parameter key="monolog.handler.native_mailer.class">Monolog\Handler\NativeMailerHandler</parameter>
<parameter key="monolog.handler.fingers_crossed.class">Monolog\Handler\FingersCrossedHandler</parameter>
<parameter key="monolog.handler.fingers_crossed.error_level_activation_strategy.class">Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy</parameter>
</parameters>
<services>
<service id="monolog.logger" parent="monolog.logger_prototype" public="false">
<argument index="0">app</argument>
</service>
<service id="logger" alias="monolog.logger" />
<service id="monolog.logger_prototype" class="%monolog.logger.class%" abstract="true">
<argument /><!-- Channel -->
</service>
</services>
</container>

View File

@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns="http://symfony.com/schema/dic/monolog"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://symfony.com/schema/dic/monolog"
elementFormDefault="qualified">
<xsd:element name="config" type="config" />
<xsd:complexType name="config">
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="handler" type="handler" />
</xsd:choice>
</xsd:complexType>
<xsd:complexType name="handler">
<xsd:sequence>
<xsd:element name="email-prototype" type="email-prototype" minOccurs="0" maxOccurs="1" />
<xsd:element name="member" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="channels" type="channels" minOccurs="0" maxOccurs="1" />
<xsd:element name="publisher" type="publisher" minOccurs="0" maxOccurs="1" />
</xsd:sequence>
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="priority" type="xsd:integer" />
<xsd:attribute name="level" type="level" />
<xsd:attribute name="bubble" type="xsd:boolean" />
<xsd:attribute name="path" type="xsd:string" />
<xsd:attribute name="id" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" use="required" />
<xsd:attribute name="ident" type="xsd:string" />
<xsd:attribute name="facility" type="xsd:string" />
<xsd:attribute name="action-level" type="level" />
<xsd:attribute name="buffer-size" type="xsd:integer" />
<xsd:attribute name="max-files" type="xsd:integer" />
<xsd:attribute name="handler" type="xsd:string" />
<xsd:attribute name="from-email" type="xsd:string" />
<xsd:attribute name="to-email" type="xsd:string" />
<xsd:attribute name="subject" type="xsd:string" />
<xsd:attribute name="formatter" type="xsd:string" />
</xsd:complexType>
<xsd:simpleType name="level">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="debug" />
<xsd:enumeration value="info" />
<xsd:enumeration value="warning" />
<xsd:enumeration value="error" />
<xsd:enumeration value="critical" />
<xsd:enumeration value="alert" />
<xsd:enumeration value="DEBUG" />
<xsd:enumeration value="INFO" />
<xsd:enumeration value="WARNING" />
<xsd:enumeration value="ERROR" />
<xsd:enumeration value="CRITICAL" />
<xsd:enumeration value="ALERT" />
<xsd:enumeration value="100" />
<xsd:enumeration value="200" />
<xsd:enumeration value="300" />
<xsd:enumeration value="400" />
<xsd:enumeration value="500" />
<xsd:enumeration value="550" />
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="publisher">
<xsd:attribute name="id" type="xsd:string" />
<xsd:attribute name="hostname" type="xsd:string" />
<xsd:attribute name="port" type="xsd:integer" />
<xsd:attribute name="chunk_size" type="xsd:integer" />
</xsd:complexType>
<xsd:complexType name="email-prototype">
<xsd:attribute name="id" type="xsd:string" />
<xsd:attribute name="method" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="channels">
<xsd:sequence>
<xsd:element name="channel" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="type" type="xsd:string" />
</xsd:complexType>
<xsd:simpleType name="channel_type">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="inclusive" />
<xsd:enumeration value="exclusive" />
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>

View File

@@ -0,0 +1,67 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\MonologBundle\Tests\DependencyInjection\Compiler;
use Symfony\Bundle\MonologBundle\DependencyInjection\Compiler\AddProcessorsPass;
use Symfony\Bundle\MonologBundle\Tests\TestCase;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
class AddProcessorsPassTest extends TestCase
{
public function testHandlerProcessors()
{
$container = $this->getContainer();
$service = $container->getDefinition('monolog.handler.test');
$calls = $service->getMethodCalls();
$this->assertCount(1, $calls);
$this->assertEquals(array('pushProcessor', array(new Reference('test'))), $calls[0]);
$service = $container->getDefinition('handler_test');
$calls = $service->getMethodCalls();
$this->assertCount(1, $calls);
$this->assertEquals(array('pushProcessor', array(new Reference('test2'))), $calls[0]);
}
protected function getContainer()
{
$container = new ContainerBuilder();
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../../../Resources/config'));
$loader->load('monolog.xml');
$definition = $container->getDefinition('monolog.logger_prototype');
$container->setDefinition('monolog.handler.test', new Definition('%monolog.handler.null.class%', array (100, false)));
$container->setDefinition('handler_test', new Definition('%monolog.handler.null.class%', array (100, false)));
$container->setAlias('monolog.handler.test2', 'handler_test');
$definition->addMethodCall('pushHandler', array(new Reference('monolog.handler.test')));
$definition->addMethodCall('pushHandler', array(new Reference('monolog.handler.test2')));
$service = new Definition('TestClass', array('false', new Reference('logger')));
$service->addTag('monolog.processor', array ('handler' => 'test'));
$container->setDefinition('test', $service);
$service = new Definition('TestClass', array('false', new Reference('logger')));
$service->addTag('monolog.processor', array ('handler' => 'test2'));
$container->setDefinition('test2', $service);
$container->getCompilerPassConfig()->setOptimizationPasses(array());
$container->getCompilerPassConfig()->setRemovingPasses(array());
$container->addCompilerPass(new AddProcessorsPass());
$container->compile();
return $container;
}
}

View File

@@ -0,0 +1,130 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\MonologBundle\Tests\DependencyInjection\Compiler;
use Symfony\Bundle\MonologBundle\Tests\TestCase;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Bundle\MonologBundle\DependencyInjection\Compiler\LoggerChannelPass;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
class LoggerChannelPassTest extends TestCase
{
public function testProcess()
{
$container = $this->getContainer();
$this->assertTrue($container->hasDefinition('monolog.logger.test'), '->process adds a logger service for tagged service');
$service = $container->getDefinition('test');
$this->assertEquals('monolog.logger.test', (string) $service->getArgument(1), '->process replaces the logger by the new one');
// pushHandlers for service "test"
$expected = array(
'test' => array('monolog.handler.a', 'monolog.handler.b', 'monolog.handler.c'),
'foo' => array('monolog.handler.b'),
'bar' => array('monolog.handler.b', 'monolog.handler.c'),
);
foreach ($expected as $serviceName => $handlers) {
$service = $container->getDefinition($serviceName);
$channel = $container->getDefinition((string) $service->getArgument(1));
$calls = $channel->getMethodCalls();
$this->assertCount(count($handlers), $calls);
foreach ($handlers as $i => $handler) {
list($methodName, $arguments) = $calls[$i];
$this->assertEquals('pushHandler', $methodName);
$this->assertCount(1, $arguments);
$this->assertEquals($handler, (string) $arguments[0]);
}
}
}
public function testProcessSetters()
{
$container = $this->getContainerWithSetter();
$this->assertTrue($container->hasDefinition('monolog.logger.test'), '->process adds a logger service for tagged service');
$service = $container->getDefinition('foo');
$calls = $service->getMethodCalls();
$this->assertEquals('monolog.logger.test', (string) $calls[0][1][0], '->process replaces the logger by the new one in setters');
}
protected function getContainer()
{
$container = new ContainerBuilder();
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../../../Resources/config'));
$loader->load('monolog.xml');
$definition = $container->getDefinition('monolog.logger_prototype');
$container->set('monolog.handler.test', new Definition('%monolog.handler.null.class%', array (100, false)));
$definition->addMethodCall('pushHandler', array(new Reference('monolog.handler.test')));
// Handlers
$container->set('monolog.handler.a', new Definition('%monolog.handler.null.class%', array (100, false)));
$container->set('monolog.handler.b', new Definition('%monolog.handler.null.class%', array (100, false)));
$container->set('monolog.handler.c', new Definition('%monolog.handler.null.class%', array (100, false)));
// Channels
foreach (array('test', 'foo', 'bar') as $name) {
$service = new Definition('TestClass', array('false', new Reference('logger')));
$service->addTag('monolog.logger', array ('channel' => $name));
$container->setDefinition($name, $service);
}
$container->setParameter('monolog.handlers_to_channels', array(
'monolog.handler.a' => array(
'type' => 'inclusive',
'elements' => array('test')
),
'monolog.handler.b' => null,
'monolog.handler.c' => array(
'type' => 'exclusive',
'elements' => array('foo')
)
));
$container->getCompilerPassConfig()->setOptimizationPasses(array());
$container->getCompilerPassConfig()->setRemovingPasses(array());
$container->addCompilerPass(new LoggerChannelPass());
$container->compile();
return $container;
}
protected function getContainerWithSetter()
{
$container = new ContainerBuilder();
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../../../Resources/config'));
$loader->load('monolog.xml');
$definition = $container->getDefinition('monolog.logger_prototype');
$container->set('monolog.handler.test', new Definition('%monolog.handler.null.class%', array (100, false)));
$definition->addMethodCall('pushHandler', array(new Reference('monolog.handler.test')));
// Channels
$service = new Definition('TestClass');
$service->addTag('monolog.logger', array ('channel' => 'test'));
$service->addMethodCall('setLogger', array(new Reference('logger')));
$container->setDefinition('foo', $service);
$container->setParameter('monolog.handlers_to_channels', array());
$container->getCompilerPassConfig()->setOptimizationPasses(array());
$container->getCompilerPassConfig()->setRemovingPasses(array());
$container->addCompilerPass(new LoggerChannelPass());
$container->compile();
return $container;
}
}

View File

@@ -0,0 +1,228 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\MonologBundle\Tests\DependencyInjection;
use Symfony\Bundle\MonologBundle\DependencyInjection\Configuration;
use Symfony\Component\Config\Definition\Processor;
class ConfigurationTest extends \PHPUnit_Framework_TestCase
{
/**
* Some basic tests to make sure the configuration is correctly processed in
* the standard case.
*/
public function testProcessSimpleCase()
{
$configs = array(
array(
'handlers' => array('foobar' => array('type' => 'stream', 'path' => '/foo/bar'))
)
);
$config = $this->process($configs);
$this->assertArrayHasKey('handlers', $config);
$this->assertArrayHasKey('foobar', $config['handlers']);
$this->assertEquals('stream', $config['handlers']['foobar']['type']);
$this->assertEquals('/foo/bar', $config['handlers']['foobar']['path']);
}
public function provideProcessStringChannels()
{
return array(
array('foo', 'foo', true),
array('!foo', 'foo', false)
);
}
/**
* @dataProvider provideProcessStringChannels
*/
public function testProcessStringChannels($string, $expectedString, $isInclusive)
{
$configs = array(
array(
'handlers' => array(
'foobar' => array(
'type' => 'stream',
'path' => '/foo/bar',
'channels' => $string
)
)
)
);
$config = $this->process($configs);
$this->assertEquals($isInclusive ? 'inclusive' : 'exclusive', $config['handlers']['foobar']['channels']['type']);
$this->assertCount(1, $config['handlers']['foobar']['channels']['elements']);
$this->assertEquals($expectedString, $config['handlers']['foobar']['channels']['elements'][0]);
}
public function provideGelfPublisher()
{
return array(
array(
'gelf.publisher'
),
array(
array(
'id' => 'gelf.publisher'
)
)
);
}
/**
* @dataProvider provideGelfPublisher
*/
public function testGelfPublisherService($publisher)
{
$configs = array(
array(
'handlers' => array(
'gelf' => array(
'type' => 'gelf',
'publisher' => $publisher,
),
)
)
);
$config = $this->process($configs);
$this->assertArrayHasKey('id', $config['handlers']['gelf']['publisher']);
$this->assertArrayNotHasKey('hostname', $config['handlers']['gelf']['publisher']);
$this->assertEquals('gelf.publisher', $config['handlers']['gelf']['publisher']['id']);
}
public function testArrays()
{
$configs = array(
array(
'handlers' => array(
'foo' => array(
'type' => 'stream',
'path' => '/foo',
'channels' => array('A', 'B')
),
'bar' => array(
'type' => 'stream',
'path' => '/foo',
'channels' => array('!C', '!D')
),
)
)
);
$config = $this->process($configs);
// Check foo
$this->assertCount(2, $config['handlers']['foo']['channels']['elements']);
$this->assertEquals('inclusive', $config['handlers']['foo']['channels']['type']);
$this->assertEquals('A', $config['handlers']['foo']['channels']['elements'][0]);
$this->assertEquals('B', $config['handlers']['foo']['channels']['elements'][1]);
// Check bar
$this->assertCount(2, $config['handlers']['bar']['channels']['elements']);
$this->assertEquals('exclusive', $config['handlers']['bar']['channels']['type']);
$this->assertEquals('C', $config['handlers']['bar']['channels']['elements'][0]);
$this->assertEquals('D', $config['handlers']['bar']['channels']['elements'][1]);
}
/**
* @expectedException Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
*/
public function testInvalidArrays()
{
$configs = array(
array(
'handlers' => array(
'foo' => array(
'type' => 'stream',
'path' => '/foo',
'channels' => array('A', '!B')
)
)
)
);
$config = $this->process($configs);
}
/**
* @expectedException Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
*/
public function testMergingInvalidChannels()
{
$configs = array(
array(
'handlers' => array(
'foo' => array(
'type' => 'stream',
'path' => '/foo',
'channels' => 'A',
)
)
),
array(
'handlers' => array(
'foo' => array(
'channels' => '!B',
)
)
)
);
$config = $this->process($configs);
}
public function testWithType()
{
$configs = array(
array(
'handlers' => array(
'foo' => array(
'type' => 'stream',
'path' => '/foo',
'channels' => array(
'type' => 'inclusive',
'elements' => array('A', 'B')
)
)
)
)
);
$config = $this->process($configs);
// Check foo
$this->assertCount(2, $config['handlers']['foo']['channels']['elements']);
$this->assertEquals('inclusive', $config['handlers']['foo']['channels']['type']);
$this->assertEquals('A', $config['handlers']['foo']['channels']['elements'][0]);
$this->assertEquals('B', $config['handlers']['foo']['channels']['elements'][1]);
}
/**
* Processes an array of configurations and returns a compiled version.
*
* @param array $configs An array of raw configurations
*
* @return array A normalized array
*/
protected function process($configs)
{
$processor = new Processor();
return $processor->processConfiguration(new Configuration(), $configs);
}
}

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" ?>
<srv:container xmlns="http://symfony.com/schema/dic/monolog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:srv="http://symfony.com/schema/dic/services"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/monolog http://symfony.com/schema/dic/monolog/monolog-1.0.xsd">
<config>
<handler name="custom" type="stream" path="/tmp/symfony.log" bubble="false" level="ERROR">
<channels>
<channel>foo</channel>
</channels>
</handler>
<handler name="main" type="group" handler="nested">
<member>nested</member>
<channels>
<channel>!foo</channel>
<channel>!bar</channel>
</channels>
</handler>
<handler name="nested" type="stream" />
<handler name="extra" type="syslog" ident="monolog" facility="user" level="ALERT" />
<handler name="more" type="native_mailer" to-email="monitoring@example.org" from-email="webmaster@example.org" subject="Monolog report" level="CRITICAL">
<channels type="inclusive">
<channel>security</channel>
<channel>doctrine</channel>
</channels>
</handler>
</config>
</srv:container>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" ?>
<srv:container xmlns="http://symfony.com/schema/dic/monolog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:srv="http://symfony.com/schema/dic/services"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/monolog http://symfony.com/schema/dic/monolog/monolog-1.0.xsd">
<config>
<handler name="custom" type="stream" path="/tmp/symfony.log" bubble="false" level="ERROR" />
<handler name="main" type="fingers_crossed" action-level="ERROR" handler="nested" />
<handler name="nested" type="stream" />
</config>
</srv:container>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" ?>
<srv:container xmlns="http://symfony.com/schema/dic/monolog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:srv="http://symfony.com/schema/dic/services"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/monolog http://symfony.com/schema/dic/monolog/monolog-1.0.xsd">
<srv:imports>
<srv:import resource="new_and_priority_import.xml" />
</srv:imports>
<config>
<handler name="custom" type="stream" path="/tmp/symfony.log" bubble="true" level="WARNING" />
<handler name="first" type="rotating_file" path="/tmp/monolog.log" bubble="true" level="ERROR" priority="3" />
<handler name="last" type="stream" path="/tmp/last.log" bubble="true" level="ERROR" priority="-3" />
</config>
</srv:container>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" ?>
<srv:container xmlns="http://symfony.com/schema/dic/monolog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:srv="http://symfony.com/schema/dic/services"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/monolog http://symfony.com/schema/dic/monolog/monolog-1.0.xsd">
<config>
<handler name="custom" type="stream" path="/tmp/symfony.log" bubble="true" level="ERROR" />
<handler name="main" type="buffer" level="INFO" handler="nested" />
<handler name="nested" type="stream" />
</config>
</srv:container>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" ?>
<srv:container xmlns="http://symfony.com/schema/dic/monolog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:srv="http://symfony.com/schema/dic/services"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/monolog http://symfony.com/schema/dic/monolog/monolog-1.0.xsd">
<srv:imports>
<srv:import resource="new_at_end_import.xml" />
</srv:imports>
<config>
<handler name="custom" type="stream" path="/tmp/symfony.log" bubble="false" level="WARNING" />
<handler name="new" type="stream" path="/tmp/monolog.log" bubble="true" level="ERROR" />
</config>
</srv:container>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" ?>
<srv:container xmlns="http://symfony.com/schema/dic/monolog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:srv="http://symfony.com/schema/dic/services"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/monolog http://symfony.com/schema/dic/monolog/monolog-1.0.xsd">
<config>
<handler name="custom" type="stream" path="/tmp/symfony.log" bubble="true" level="ERROR" />
<handler name="main" type="fingers_crossed" action-level="ERROR" handler="nested" />
<handler name="nested" type="stream" />
</config>
</srv:container>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" ?>
<srv:container xmlns="http://symfony.com/schema/dic/monolog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:srv="http://symfony.com/schema/dic/services"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/monolog http://symfony.com/schema/dic/monolog/monolog-1.0.xsd">
<srv:imports>
<srv:import resource="overwriting_import.xml" />
</srv:imports>
<config>
<handler name="custom" type="stream" path="/tmp/symfony.log" bubble="true" level="WARNING" />
</config>
</srv:container>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" ?>
<srv:container xmlns="http://symfony.com/schema/dic/monolog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:srv="http://symfony.com/schema/dic/services"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/monolog http://symfony.com/schema/dic/monolog/monolog-1.0.xsd">
<config>
<handler name="custom" type="stream" path="/tmp/symfony.log" bubble="false" level="ERROR" />
<handler name="main" type="fingers_crossed" action-level="ERROR" handler="nested" />
<handler name="nested" type="stream" />
</config>
</srv:container>

View File

@@ -0,0 +1,30 @@
monolog:
handlers:
custom:
type: stream
path: /tmp/symfony.log
bubble: false
level: ERROR
channels: foo
main:
type: group
members: [nested]
channels: ["!foo", "!bar"]
nested:
type: stream
extra:
type: syslog
ident: monolog
facility: user
level: ALERT
more:
type: native_mailer
to_email: monitoring@example.org
from_email: webmaster@example.org
subject: Monolog report
level: CRITICAL
channels:
type: inclusive
elements:
- security
- doctrine

View File

@@ -0,0 +1,13 @@
monolog:
handlers:
custom:
type: stream
path: /tmp/symfony.log
bubble: false
level: ERROR
main:
type: fingers_crossed
action_level: ERROR
handler: nested
nested:
type: stream

View File

@@ -0,0 +1,22 @@
imports:
- { resource: new_and_priority_import.yml }
monolog:
handlers:
custom:
type: stream
path: /tmp/symfony.log
bubble: true
level: WARNING
first:
type: rotating_file
path: /tmp/monolog.log
bubble: true
level: ERROR
priority: 3
last:
type: stream
path: /tmp/last.log
bubble: true
level: ERROR
priority: -3

View File

@@ -0,0 +1,13 @@
monolog:
handlers:
custom:
type: stream
path: /tmp/symfony.log
bubble: true
level: ERROR
main:
type: buffer
level: INFO
handler: nested
nested:
type: stream

View File

@@ -0,0 +1,15 @@
imports:
- { resource: new_at_end_import.yml }
monolog:
handlers:
custom:
type: stream
path: /tmp/symfony.log
bubble: false
level: WARNING
new:
type: stream
path: /tmp/monolog.log
bubble: true
level: ERROR

View File

@@ -0,0 +1,13 @@
monolog:
handlers:
custom:
type: stream
path: /tmp/symfony.log
bubble: true
level: ERROR
main:
type: fingers_crossed
action_level: ERROR
handler: nested
nested:
type: stream

View File

@@ -0,0 +1,10 @@
imports:
- { resource: overwriting_import.yml }
monolog:
handlers:
custom:
type: stream
path: /tmp/symfony.log
bubble: true
level: WARNING

View File

@@ -0,0 +1,13 @@
monolog:
handlers:
custom:
type: stream
path: /tmp/symfony.log
bubble: false
level: ERROR
main:
type: fingers_crossed
action_level: ERROR
handler: nested
nested:
type: stream

View File

@@ -0,0 +1,285 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\MonologBundle\Tests\DependencyInjection;
use Symfony\Bundle\MonologBundle\Tests\TestCase;
use Symfony\Bundle\MonologBundle\DependencyInjection\MonologExtension;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
abstract class MonologExtensionTest extends TestCase
{
public function testLoadWithDefault()
{
$container = new ContainerBuilder();
$loader = new MonologExtension();
$loader->load(array(array('handlers' => array('main' => array('type' => 'stream')))), $container);
$this->assertTrue($container->hasDefinition('monolog.logger'));
$this->assertTrue($container->hasDefinition('monolog.handler.main'));
$logger = $container->getDefinition('monolog.logger');
$this->assertDICDefinitionMethodCallAt(0, $logger, 'pushHandler', array(new Reference('monolog.handler.main')));
$handler = $container->getDefinition('monolog.handler.main');
$this->assertDICDefinitionClass($handler, '%monolog.handler.stream.class%');
$this->assertDICConstructorArguments($handler, array('%kernel.logs_dir%/%kernel.environment%.log', \Monolog\Logger::DEBUG, true));
}
public function testLoadWithCustomValues()
{
$container = new ContainerBuilder();
$loader = new MonologExtension();
$loader->load(array(array('handlers' => array('custom' => array('type' => 'stream', 'path' => '/tmp/symfony.log', 'bubble' => false, 'level' => 'ERROR')))), $container);
$this->assertTrue($container->hasDefinition('monolog.logger'));
$this->assertTrue($container->hasDefinition('monolog.handler.custom'));
$logger = $container->getDefinition('monolog.logger');
$this->assertDICDefinitionMethodCallAt(0, $logger, 'pushHandler', array(new Reference('monolog.handler.custom')));
$handler = $container->getDefinition('monolog.handler.custom');
$this->assertDICDefinitionClass($handler, '%monolog.handler.stream.class%');
$this->assertDICConstructorArguments($handler, array('/tmp/symfony.log', \Monolog\Logger::ERROR, false));
}
public function testLoadWithSeveralHandlers()
{
$container = $this->getContainer('multiple_handlers');
$this->assertTrue($container->hasDefinition('monolog.logger'));
$this->assertTrue($container->hasDefinition('monolog.handler.custom'));
$this->assertTrue($container->hasDefinition('monolog.handler.main'));
$this->assertTrue($container->hasDefinition('monolog.handler.nested'));
$logger = $container->getDefinition('monolog.logger');
$this->assertDICDefinitionMethodCallAt(1, $logger, 'pushHandler', array(new Reference('monolog.handler.custom')));
$this->assertDICDefinitionMethodCallAt(0, $logger, 'pushHandler', array(new Reference('monolog.handler.main')));
$handler = $container->getDefinition('monolog.handler.custom');
$this->assertDICDefinitionClass($handler, '%monolog.handler.stream.class%');
$this->assertDICConstructorArguments($handler, array('/tmp/symfony.log', \Monolog\Logger::ERROR, false));
$handler = $container->getDefinition('monolog.handler.main');
$this->assertDICDefinitionClass($handler, '%monolog.handler.fingers_crossed.class%');
$this->assertDICConstructorArguments($handler, array(new Reference('monolog.handler.nested'), \Monolog\Logger::ERROR, 0, true, true));
}
public function testLoadWithOverwriting()
{
$container = $this->getContainer('overwriting');
$this->assertTrue($container->hasDefinition('monolog.logger'));
$this->assertTrue($container->hasDefinition('monolog.handler.custom'));
$this->assertTrue($container->hasDefinition('monolog.handler.main'));
$this->assertTrue($container->hasDefinition('monolog.handler.nested'));
$logger = $container->getDefinition('monolog.logger');
$this->assertDICDefinitionMethodCallAt(1, $logger, 'pushHandler', array(new Reference('monolog.handler.custom')));
$this->assertDICDefinitionMethodCallAt(0, $logger, 'pushHandler', array(new Reference('monolog.handler.main')));
$handler = $container->getDefinition('monolog.handler.custom');
$this->assertDICDefinitionClass($handler, '%monolog.handler.stream.class%');
$this->assertDICConstructorArguments($handler, array('/tmp/symfony.log', \Monolog\Logger::WARNING, true));
$handler = $container->getDefinition('monolog.handler.main');
$this->assertDICDefinitionClass($handler, '%monolog.handler.fingers_crossed.class%');
$this->assertDICConstructorArguments($handler, array(new Reference('monolog.handler.nested'), \Monolog\Logger::ERROR, 0, true, true));
}
public function testLoadWithNewAtEnd()
{
$container = $this->getContainer('new_at_end');
$this->assertTrue($container->hasDefinition('monolog.logger'));
$this->assertTrue($container->hasDefinition('monolog.handler.custom'));
$this->assertTrue($container->hasDefinition('monolog.handler.main'));
$this->assertTrue($container->hasDefinition('monolog.handler.nested'));
$this->assertTrue($container->hasDefinition('monolog.handler.new'));
$logger = $container->getDefinition('monolog.logger');
$this->assertDICDefinitionMethodCallAt(2, $logger, 'pushHandler', array(new Reference('monolog.handler.new')));
$this->assertDICDefinitionMethodCallAt(1, $logger, 'pushHandler', array(new Reference('monolog.handler.custom')));
$this->assertDICDefinitionMethodCallAt(0, $logger, 'pushHandler', array(new Reference('monolog.handler.main')));
$handler = $container->getDefinition('monolog.handler.new');
$this->assertDICDefinitionClass($handler, '%monolog.handler.stream.class%');
$this->assertDICConstructorArguments($handler, array('/tmp/monolog.log', \Monolog\Logger::ERROR, true));
}
public function testLoadWithNewAndPriority()
{
$container = $this->getContainer('new_and_priority');
$this->assertTrue($container->hasDefinition('monolog.logger'));
$this->assertTrue($container->hasDefinition('monolog.handler.custom'));
$this->assertTrue($container->hasDefinition('monolog.handler.main'));
$this->assertTrue($container->hasDefinition('monolog.handler.nested'));
$this->assertTrue($container->hasDefinition('monolog.handler.first'));
$this->assertTrue($container->hasDefinition('monolog.handler.last'));
$logger = $container->getDefinition('monolog.logger');
$this->assertDICDefinitionMethodCallAt(2, $logger, 'pushHandler', array(new Reference('monolog.handler.last')));
$this->assertDICDefinitionMethodCallAt(1, $logger, 'pushHandler', array(new Reference('monolog.handler.custom')));
$this->assertDICDefinitionMethodCallAt(0, $logger, 'pushHandler', array(new Reference('monolog.handler.main')));
$this->assertDICDefinitionMethodCallAt(2, $logger, 'pushHandler', array(new Reference('monolog.handler.first')));
$handler = $container->getDefinition('monolog.handler.main');
$this->assertDICDefinitionClass($handler, '%monolog.handler.buffer.class%');
$this->assertDICConstructorArguments($handler, array(new Reference('monolog.handler.nested'), 0, \Monolog\Logger::INFO, true));
$handler = $container->getDefinition('monolog.handler.first');
$this->assertDICDefinitionClass($handler, '%monolog.handler.rotating_file.class%');
$this->assertDICConstructorArguments($handler, array('/tmp/monolog.log', 0, \Monolog\Logger::ERROR, true));
$handler = $container->getDefinition('monolog.handler.last');
$this->assertDICDefinitionClass($handler, '%monolog.handler.stream.class%');
$this->assertDICConstructorArguments($handler, array('/tmp/last.log', \Monolog\Logger::ERROR, true));
}
public function testHandlersWithChannels()
{
$container = $this->getContainer('handlers_with_channels');
$this->assertEquals(
array(
'monolog.handler.custom' => array('type' => 'inclusive', 'elements' => array('foo')),
'monolog.handler.main' => array('type' => 'exclusive', 'elements' => array('foo', 'bar')),
'monolog.handler.extra' => null,
'monolog.handler.more' => array('type' => 'inclusive', 'elements' => array('security', 'doctrine')),
),
$container->getParameter('monolog.handlers_to_channels')
);
}
/**
* @expectedException InvalidArgumentException
*/
public function testExceptionWhenInvalidHandler()
{
$container = new ContainerBuilder();
$loader = new MonologExtension();
$loader->load(array(array('handlers' => array('main' => array('type' => 'invalid_handler')))), $container);
}
/**
* @expectedException Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
*/
public function testExceptionWhenUsingFingerscrossedWithoutHandler()
{
$container = new ContainerBuilder();
$loader = new MonologExtension();
$loader->load(array(array('handlers' => array('main' => array('type' => 'fingers_crossed')))), $container);
}
/**
* @expectedException Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
*/
public function testExceptionWhenUsingBufferWithoutHandler()
{
$container = new ContainerBuilder();
$loader = new MonologExtension();
$loader->load(array(array('handlers' => array('main' => array('type' => 'buffer')))), $container);
}
/**
* @expectedException Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
*/
public function testExceptionWhenUsingGelfWithoutPublisher()
{
$container = new ContainerBuilder();
$loader = new MonologExtension();
$loader->load(array(array('handlers' => array('gelf' => array('type' => 'gelf')))), $container);
}
/**
* @expectedException Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
*/
public function testExceptionWhenUsingGelfWithoutPublisherHostname()
{
$container = new ContainerBuilder();
$loader = new MonologExtension();
$loader->load(array(array('handlers' => array('gelf' => array('type' => 'gelf', 'publisher' => array())))), $container);
}
/**
* @expectedException Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
*/
public function testExceptionWhenUsingServiceWithoutId()
{
$container = new ContainerBuilder();
$loader = new MonologExtension();
$loader->load(array(array('handlers' => array('main' => array('type' => 'service')))), $container);
}
/**
* @expectedException Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
*/
public function testExceptionWhenUsingDebugName()
{
// logger
$container = new ContainerBuilder();
$loader = new MonologExtension();
$loader->load(array(array('handlers' => array('debug' => array('type' => 'stream')))), $container);
}
protected function getContainer($fixture)
{
$container = new ContainerBuilder();
$container->registerExtension(new MonologExtension());
$this->loadFixture($container, $fixture);
$container->getCompilerPassConfig()->setOptimizationPasses(array());
$container->getCompilerPassConfig()->setRemovingPasses(array());
$container->compile();
return $container;
}
abstract protected function loadFixture(ContainerBuilder $container, $fixture);
/**
* Assertion on the Class of a DIC Service Definition.
*
* @param \Symfony\Component\DependencyInjection\Definition $definition
* @param string $expectedClass
*/
protected function assertDICDefinitionClass($definition, $expectedClass)
{
$this->assertEquals($expectedClass, $definition->getClass(), "Expected Class of the DIC Container Service Definition is wrong.");
}
protected function assertDICConstructorArguments($definition, $args)
{
$this->assertEquals($args, $definition->getArguments(), "Expected and actual DIC Service constructor arguments of definition '".$definition->getClass()."' don't match.");
}
protected function assertDICDefinitionMethodCallAt($pos, $definition, $methodName, array $params = null)
{
$calls = $definition->getMethodCalls();
if (isset($calls[$pos][0])) {
$this->assertEquals($methodName, $calls[$pos][0], "Method '".$methodName."' is expected to be called at position $pos.");
if ($params !== null) {
$this->assertEquals($params, $calls[$pos][1], "Expected parameters to methods '".$methodName."' do not match the actual parameters.");
}
}
}
}

View File

@@ -0,0 +1,25 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\MonologBundle\Tests\DependencyInjection;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
class XmlMonologExtensionTest extends MonologExtensionTest
{
protected function loadFixture(ContainerBuilder $container, $fixture)
{
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/Fixtures/xml'));
$loader->load($fixture.'.xml');
}
}

View File

@@ -0,0 +1,25 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\MonologBundle\Tests\DependencyInjection;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
class YamlMonologExtensionTest extends MonologExtensionTest
{
protected function loadFixture(ContainerBuilder $container, $fixture)
{
$loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/Fixtures/yml'));
$loader->load($fixture.'.yml');
}
}

View File

@@ -0,0 +1,22 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\MonologBundle\Tests;
class TestCase extends \PHPUnit_Framework_TestCase
{
protected function setUp()
{
if (!class_exists('Monolog\\Logger')) {
$this->markTestSkipped('Monolog is not available.');
}
}
}

View File

@@ -0,0 +1,19 @@
<?php
if (!@include __DIR__ . '/../vendor/.composer/autoload.php') {
die("You must set up the project dependencies, run the following commands:
wget http://getcomposer.org/composer.phar
php composer.phar install
");
}
spl_autoload_register(function($class) {
if (0 === strpos($class, 'Symfony\\Bundle\\MonologBundle')) {
$path = __DIR__.'/../'.implode('/', array_slice(explode('\\', $class), 3)).'.php';
if (!stream_resolve_include_path($path)) {
return false;
}
require_once $path;
return true;
}
});

View File

@@ -0,0 +1,37 @@
{
"name": "symfony/monolog-bundle",
"type": "symfony-bundle",
"description": "Symfony MonologBundle",
"keywords": [],
"homepage": "http://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "http://symfony.com/contributors"
}
],
"require": {
"php": ">=5.3.2",
"symfony/monolog-bridge": "2.1.*",
"symfony/dependency-injection": "2.1.*",
"symfony/config": "2.1.*",
"monolog/monolog": "1.*"
},
"require-dev": {
"symfony/yaml": "2.1.*"
},
"autoload": {
"psr-0": { "Symfony\\Bundle\\MonologBundle": "" }
},
"target-dir": "Symfony/Bundle/MonologBundle",
"extra": {
"branch-alias": {
"dev-master": "2.1.x-dev"
}
}
}

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit colors="true" bootstrap="Tests/bootstrap.php">
<testsuites>
<testsuite name="MonologBundle for the Symfony Framework">
<directory>./Tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>.</directory>
<exclude>
<directory>./Resources</directory>
<directory>./Tests</directory>
<directory>./vendor</directory>
</exclude>
</whitelist>
</filter>
</phpunit>