这并不像看起来那么容易。处理器根据logger 或handler 注册。
如果处理器在记录器中注册,则无法知道处理器经历了哪个处理程序,就像所有处理程序are executed after all processors were executed一样。如果你在一个 handler 上注册处理器,你总是知道执行的是哪个 handler,但是手动为每个 handler 注册一个处理器是相当麻烦的。
为了解决这个问题,您可以添加一个CompilerPass,它会为您完成手动工作。
假设我们有这个处理器
class HandlerProcessor
{
/**
* @var string
*/
private $handlerName;
public function __construct($handlerName)
{
$this->handlerName = $handlerName;
}
public function processRecord(array $record)
{
$record['extra']['handler_name'] = $this->handlerName;
return $record;
}
}
使用这个处理器,您可以创建一个编译器通道,它为创建的不同处理程序 monolog 创建所有定义
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
class HandlerProcessorPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasParameter('monolog.handlers_to_channels')) {
return;
}
foreach ($container->getParameter('monolog.handlers_to_channels') as $handlerId => $channels) {
$definition = new Definition(HandlerProcessor::class);
$handlerDefinition = $container->getDefinition($handlerId);
$handlerName = $handlerDefinition->getClass();
$definition->addArgument($handlerName);
$handlerProcessorId = 'handler_processor.' . $handlerId;
$container->setDefinition($handlerProcessorId, $definition);
$handlerDefinition->addMethodCall('pushProcessor', array(new Reference($handlerProcessorId)));
}
}
}
如果您以前从未使用过编译器传递可能会非常混乱,让我们逐行进行:
if (!$container->hasParameter('monolog.handlers_to_channels')) {
return;
}
这将检查独白包是否已注册。参数monolog.handlers_to_channels 被添加到MonologExtension 中的容器中。参数本身包含一个数组,其中键是处理程序 ID 的名称,值是一个包含此处理程序注册到的所有通道的数组(如果此处理程序对所有通道都有效,则为 null)
foreach ($container->getParameter('monolog.handlers_to_channels') as $handlerId => $channels) {
$definition = new Definition(HandlerProcessor::class);
$handlerDefinition = $container->getDefinition($handlerId);
这里我们为HandlerProcessor创建一个新定义,并获取当前处理的处理程序的定义。
$handlerName = $handlerDefinition->getClass();
$definition->addArgument($handlerName);
这将获取处理程序的类名(例如Monolog\Handler\SlackHandler)并将其作为构造函数参数添加到HandlerProcessor
$handlerProcessorId = 'handler_processor.' . $handlerId;
$container->setDefinition($handlerProcessorId, $definition);
$handlerDefinition->addMethodCall('pushProcessor', array(new Reference($handlerProcessorId)));
最后但同样重要的是,我们为刚刚在 foreach 循环开始时创建的处理器定义创建了一个新 ID,并通过方法调用 pushProcessor 将其添加到我们新创建的处理器中。
现在一切都设置好了,你必须在你的容器中注册这个编译器通道。我假设您使用的是 symfony 2.x,所以您必须在 AppBundle
中这样做
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class AppBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
$container->addCompilerPass(new HandlerProcessorPass());
}
}
以下是一些可能有用的附加链接: