Skip to content

Commit 133cd1c

Browse files
committed
Add Sentry BreadcrumbHandler support
1 parent 58b98dc commit 133cd1c

File tree

3 files changed

+96
-14
lines changed

3 files changed

+96
-14
lines changed

DependencyInjection/Configuration.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,9 @@
236236
* - hub_id: Sentry hub custom service id (optional)
237237
* - [fill_extra_context]: bool, defaults to false
238238
*
239+
* - sentry_breadcrumb:
240+
* - sentry_handler: the sentry handler's name
241+
*
239242
* - newrelic:
240243
* - [level]: level name or int value, defaults to DEBUG
241244
* - [bubble]: bool, defaults to true
@@ -584,6 +587,7 @@ public function getConfigTreeBuilder(): TreeBuilder
584587
->booleanNode('persistent')->end() // socket_handler
585588
->scalarNode('dsn')->end() // raven_handler, sentry_handler
586589
->scalarNode('hub_id')->defaultNull()->end() // sentry_handler
590+
->scalarNode('sentry_handler')->defaultNull()->end() // sentry_breadcrumb
587591
->scalarNode('client_id')->defaultNull()->end() // raven_handler, sentry_handler
588592
->scalarNode('auto_log_stacks')->defaultFalse()->end() // raven_handler
589593
->scalarNode('release')->defaultNull()->end() // raven_handler, sentry_handler
@@ -725,6 +729,10 @@ public function getConfigTreeBuilder(): TreeBuilder
725729
->ifTrue(function ($v) { return 'sentry' === $v['type'] && null !== $v['hub_id'] && null !== $v['client_id']; })
726730
->thenInvalid('You can not use both a hub_id and a client_id in a Sentry handler')
727731
->end()
732+
->validate()
733+
->ifTrue(function ($v) { return 'sentry_breadcrumb' === $v['type'] && empty($v['sentry_handler']); })
734+
->thenInvalid('The sentry_handler has to be specified to use a Sentry BreadcrumbHandler')
735+
->end()
728736
->validate()
729737
->ifTrue(function ($v) { return 'hipchat' === $v['type'] && (empty($v['token']) || empty($v['room'])); })
730738
->thenInvalid('The token and room have to be specified to use a HipChatHandler')

DependencyInjection/MonologExtension.php

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use Symfony\Bridge\Monolog\Processor\TokenProcessor;
2626
use Symfony\Bridge\Monolog\Processor\WebProcessor;
2727
use Symfony\Component\Config\FileLocator;
28+
use Symfony\Component\DependencyInjection\Argument\AbstractArgument;
2829
use Symfony\Component\DependencyInjection\Argument\BoundArgument;
2930
use Symfony\Component\DependencyInjection\ChildDefinition;
3031
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -47,6 +48,8 @@ class MonologExtension extends Extension
4748
{
4849
private $nestedHandlers = [];
4950

51+
private $sentryBreadcrumbHandlers = [];
52+
5053
private $swiftMailerHandlers = [];
5154

5255
/**
@@ -79,6 +82,11 @@ public function load(array $configs, ContainerBuilder $container)
7982
];
8083
}
8184

85+
foreach ($this->sentryBreadcrumbHandlers as $sentryBreadcrumbHandlerId => $sentryHandlerId) {
86+
$hubId = (string) $container->getDefinition($sentryHandlerId)->getArgument(0);
87+
$container->getDefinition($sentryBreadcrumbHandlerId)->replaceArgument(0, new Reference($hubId));
88+
}
89+
8290
$container->setParameter(
8391
'monolog.swift_mailer.handlers',
8492
$this->swiftMailerHandlers
@@ -724,7 +732,7 @@ private function buildHandler(ContainerBuilder $container, $name, array $handler
724732

725733
case 'sentry':
726734
if (null !== $handler['hub_id']) {
727-
$hub = new Reference($handler['hub_id']);
735+
$hubId = $handler['hub_id'];
728736
} else {
729737
if (null !== $handler['client_id']) {
730738
$clientId = $handler['client_id'];
@@ -755,24 +763,34 @@ private function buildHandler(ContainerBuilder $container, $name, array $handler
755763
}
756764
}
757765

758-
$hub = new Definition(
766+
$hubId = \sprintf('monolog.handler.%s.hub', $name);
767+
$hub = $container->setDefinition($hubId, new Definition(
759768
'Sentry\\State\\Hub',
760769
[new Reference($clientId)]
761-
);
762-
$container->setDefinition(\sprintf('monolog.handler.%s.hub', $name), $hub);
770+
));
763771

764772
// can't set the hub to the current hub, getting into a recursion otherwise...
765773
// $hub->addMethodCall('setCurrent', array($hub));
766774
}
767775

768776
$definition->setArguments([
769-
$hub,
777+
new Reference($hubId),
770778
$handler['level'],
771779
$handler['bubble'],
772780
$handler['fill_extra_context'],
773781
]);
774782
break;
775783

784+
case 'sentry_breadcrumb':
785+
$this->sentryBreadcrumbHandlers[$handlerId] = $this->getHandlerId($handler['sentry_handler']);
786+
787+
$definition->setArguments([
788+
new AbstractArgument('Sentry hub id'),
789+
$handler['level'],
790+
$handler['bubble'],
791+
]);
792+
break;
793+
776794
case 'raven':
777795
if (null !== $handler['client_id']) {
778796
$clientId = $handler['client_id'];
@@ -977,6 +995,7 @@ private function getHandlerClassByType($handlerType)
977995
'pushover' => 'Monolog\Handler\PushoverHandler',
978996
'raven' => 'Monolog\Handler\RavenHandler',
979997
'sentry' => 'Sentry\Monolog\Handler',
998+
'sentry_breadcrumb' => 'Sentry\Monolog\BreadcrumbHandler',
980999
'newrelic' => 'Monolog\Handler\NewRelicHandler',
9811000
'hipchat' => 'Monolog\Handler\HipChatHandler',
9821001
'slack' => 'Monolog\Handler\SlackHandler',

Tests/DependencyInjection/MonologExtensionTest.php

Lines changed: 64 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -371,12 +371,10 @@ public function testRavenHandlerWhenAClientIsSpecified()
371371

372372
public function testSentryHandlerWhenConfigurationIsWrong()
373373
{
374-
try {
375-
$this->getContainer([['handlers' => ['sentry' => ['type' => 'sentry']]]]);
376-
$this->fail();
377-
} catch (InvalidConfigurationException $e) {
378-
$this->assertStringContainsString('DSN', $e->getMessage());
379-
}
374+
$this->expectException(InvalidConfigurationException::class);
375+
$this->expectExceptionMessage('The DSN has to be specified to use Sentry\'s handler');
376+
377+
$this->getContainer([['handlers' => ['sentry' => ['type' => 'sentry']]]]);
380378
}
381379

382380
public function testSentryHandlerWhenADSNIsSpecified()
@@ -396,8 +394,9 @@ public function testSentryHandlerWhenADSNIsSpecified()
396394

397395
$handler = $container->getDefinition('monolog.handler.sentry');
398396
$this->assertDICDefinitionClass($handler, 'Sentry\Monolog\Handler');
397+
$this->assertDICConstructorArguments($handler, [new Reference('monolog.handler.sentry.hub'), 'DEBUG', true, false]);
399398

400-
$hub = $container->getDefinition('monolog.handler.sentry.hub');
399+
$hub = $container->getDefinition($handler->getArguments()[0]);
401400
$this->assertDICDefinitionClass($hub, 'Sentry\State\Hub');
402401
$this->assertDICConstructorArguments($hub, [new Reference('monolog.sentry.client.'.sha1($dsn))]);
403402
}
@@ -426,7 +425,12 @@ public function testSentryHandlerWhenADSNAndAClientAreSpecified()
426425
$this->assertDICDefinitionMethodCallAt(1, $logger, 'pushHandler', [new Reference('monolog.handler.sentry')]);
427426

428427
$handler = $container->getDefinition('monolog.handler.sentry');
429-
$this->assertDICConstructorArguments($handler->getArguments()[0], [new Reference('sentry.client')]);
428+
$this->assertDICDefinitionClass($handler, 'Sentry\Monolog\Handler');
429+
$this->assertDICConstructorArguments($handler, [new Reference('monolog.handler.sentry.hub'), 'DEBUG', true, false]);
430+
431+
$hub = $container->getDefinition($handler->getArguments()[0]);
432+
$this->assertDICDefinitionClass($hub, 'Sentry\State\Hub');
433+
$this->assertDICConstructorArguments($hub, [new Reference('sentry.client')]);
430434
}
431435

432436
public function testSentryHandlerWhenAClientIsSpecified()
@@ -452,7 +456,12 @@ public function testSentryHandlerWhenAClientIsSpecified()
452456
$this->assertDICDefinitionMethodCallAt(1, $logger, 'pushHandler', [new Reference('monolog.handler.sentry')]);
453457

454458
$handler = $container->getDefinition('monolog.handler.sentry');
455-
$this->assertDICConstructorArguments($handler->getArguments()[0], [new Reference('sentry.client')]);
459+
$this->assertDICDefinitionClass($handler, 'Sentry\Monolog\Handler');
460+
$this->assertDICConstructorArguments($handler, [new Reference('monolog.handler.sentry.hub'), 'DEBUG', true, false]);
461+
462+
$hub = $container->getDefinition($handler->getArguments()[0]);
463+
$this->assertDICDefinitionClass($hub, 'Sentry\State\Hub');
464+
$this->assertDICConstructorArguments($hub, [new Reference('sentry.client')]);
456465
}
457466

458467
public function testSentryHandlerWhenAHubIsSpecified()
@@ -478,6 +487,7 @@ public function testSentryHandlerWhenAHubIsSpecified()
478487
$this->assertDICDefinitionMethodCallAt(1, $logger, 'pushHandler', [new Reference('monolog.handler.sentry')]);
479488

480489
$handler = $container->getDefinition('monolog.handler.sentry');
490+
$this->assertDICDefinitionClass($handler, 'Sentry\Monolog\Handler');
481491
$this->assertDICConstructorArguments($handler, [new Reference('sentry.hub'), 'DEBUG', true, false]);
482492
}
483493

@@ -501,6 +511,51 @@ public function testSentryHandlerWhenAHubAndAClientAreSpecified()
501511
);
502512
}
503513

514+
public function testSentryBreadcrumbHandlerWhenConfigurationIsWrong()
515+
{
516+
$this->expectException(InvalidConfigurationException::class);
517+
$this->expectExceptionMessage('The sentry_handler has to be specified to use a Sentry BreadcrumbHandler');
518+
519+
$this->getContainer([['handlers' => ['sentry_breadcrumb' => ['type' => 'sentry_breadcrumb']]]]);
520+
}
521+
522+
/**
523+
* @testWith [{"dsn": "http://a:[email protected]:9000/1"}, "monolog.handler.sentry.hub"]
524+
* [{"hub_id": "sentry.hub"}, "sentry.hub"]
525+
*/
526+
public function testSentryBreadcrumbHandlerWhenConfigurationIsOk(array $config, string $hubId)
527+
{
528+
$container = $this->getContainer(
529+
[
530+
[
531+
'handlers' => [
532+
'sentry_breadcrumb' => ['type' => 'sentry_breadcrumb', 'sentry_handler' => 'sentry'],
533+
'sentry' => ['type' => 'sentry'] + $config,
534+
],
535+
],
536+
],
537+
[
538+
'sentry.hub' => new Definition(\Sentry\State\HubInterface::class),
539+
]
540+
);
541+
542+
$this->assertTrue($container->hasDefinition('monolog.logger'));
543+
$this->assertTrue($container->hasDefinition('monolog.handler.sentry'));
544+
$this->assertTrue($container->hasDefinition('monolog.handler.sentry_breadcrumb'));
545+
546+
$logger = $container->getDefinition('monolog.logger');
547+
$this->assertDICDefinitionMethodCallAt(0, $logger, 'useMicrosecondTimestamps', ['%monolog.use_microseconds%']);
548+
$this->assertDICDefinitionMethodCallAt(1, $logger, 'pushHandler', [new Reference('monolog.handler.sentry')]);
549+
$this->assertDICDefinitionMethodCallAt(2, $logger, 'pushHandler', [new Reference('monolog.handler.sentry_breadcrumb')]);
550+
551+
$handler = $container->getDefinition('monolog.handler.sentry_breadcrumb');
552+
$this->assertDICDefinitionClass($handler, 'Sentry\Monolog\BreadcrumbHandler');
553+
$this->assertDICConstructorArguments($handler, [new Reference($hubId), 'DEBUG', true]);
554+
555+
$sentry = $container->getDefinition('monolog.handler.sentry');
556+
$this->assertSame((string) $sentry->getArgument(0), (string) $handler->getArgument(0));
557+
}
558+
504559
public function testLogglyHandler()
505560
{
506561
$token = '026308d8-2b63-4225-8fe9-e01294b6e472';

0 commit comments

Comments
 (0)