Skip to content

Commit 5229f18

Browse files
committed
fix: add buffer flusher for sentry handler
1 parent e8022fe commit 5229f18

File tree

3 files changed

+125
-0
lines changed

3 files changed

+125
-0
lines changed
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Sentry\SentryBundle\DependencyInjection\Compiler;
6+
7+
use Monolog\Handler\BufferHandler;
8+
use Sentry\Monolog\Handler as SentryHandler;
9+
use Sentry\SentryBundle\EventListener\SentryBufferFlusher;
10+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
11+
use Symfony\Component\DependencyInjection\ContainerBuilder;
12+
use Symfony\Component\DependencyInjection\Definition;
13+
use Symfony\Component\DependencyInjection\Reference;
14+
15+
class SentryBufferFlushPass implements CompilerPassInterface
16+
{
17+
public function process(ContainerBuilder $container): void
18+
{
19+
$sentryBufferHandlers = $this->findSentryBufferHandlers($container);
20+
21+
if (empty($sentryBufferHandlers)) {
22+
return;
23+
}
24+
25+
$flusherDefinition = new Definition(SentryBufferFlusher::class);
26+
$flusherDefinition->setArguments([$sentryBufferHandlers]);
27+
$flusherDefinition->addTag('kernel.event_subscriber');
28+
29+
$container->setDefinition('sentry.buffer_flusher', $flusherDefinition);
30+
}
31+
32+
/**
33+
* Finds all {@link BufferHandler} that wrap {@link SentryHandler} and register a service
34+
* that will flush them on KernelEvents::TERMINATE to make sure that all events retain
35+
* breadcrumbs and context information.
36+
*
37+
* @return Reference[]
38+
*/
39+
private function findSentryBufferHandlers(ContainerBuilder $container): array
40+
{
41+
$sentryBufferHandlers = [];
42+
43+
foreach ($container->getDefinitions() as $serviceId => $definition) {
44+
if (BufferHandler::class === $definition->getClass()) {
45+
$arguments = $definition->getArguments();
46+
if (!empty($arguments)) {
47+
// The first argument of BufferHandler is the HandlerInterface, which
48+
// can be a SentryHandler.
49+
$firstArgument = $arguments[0];
50+
51+
if ($firstArgument instanceof Reference) {
52+
$referencedServiceId = (string) $firstArgument;
53+
try {
54+
$referencedDefinition = $container->findDefinition($referencedServiceId);
55+
56+
if (SentryHandler::class === $referencedDefinition->getClass()) {
57+
$sentryBufferHandlers[] = new Reference($serviceId);
58+
}
59+
} catch (\Exception $e) {
60+
// If the service from the first argument doesn't exist we just keep going
61+
continue;
62+
}
63+
}
64+
}
65+
}
66+
}
67+
68+
return $sentryBufferHandlers;
69+
}
70+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Sentry\SentryBundle\EventListener;
6+
7+
use Monolog\Handler\BufferHandler;
8+
use Symfony\Component\Console\ConsoleEvents;
9+
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
10+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
11+
use Symfony\Component\HttpKernel\Event\TerminateEvent;
12+
use Symfony\Component\HttpKernel\KernelEvents;
13+
14+
class SentryBufferFlusher implements EventSubscriberInterface
15+
{
16+
/**
17+
* @var BufferHandler[]
18+
*/
19+
private $bufferHandlers;
20+
21+
/**
22+
* @param BufferHandler[] $bufferHandlers
23+
*/
24+
public function __construct(array $bufferHandlers = [])
25+
{
26+
$this->bufferHandlers = $bufferHandlers;
27+
}
28+
29+
public static function getSubscribedEvents(): array
30+
{
31+
return [
32+
KernelEvents::TERMINATE => ['onKernelTerminate', 10],
33+
ConsoleEvents::TERMINATE => ['onConsoleTerminate', 10],
34+
];
35+
}
36+
37+
public function onKernelTerminate(TerminateEvent $event): void
38+
{
39+
$this->flushBuffers();
40+
}
41+
42+
public function onConsoleTerminate(ConsoleTerminateEvent $event): void
43+
{
44+
$this->flushBuffers();
45+
}
46+
47+
private function flushBuffers(): void
48+
{
49+
foreach ($this->bufferHandlers as $handler) {
50+
$handler->flush();
51+
}
52+
}
53+
}

src/SentryBundle.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Sentry\SentryBundle\DependencyInjection\Compiler\CacheTracingPass;
99
use Sentry\SentryBundle\DependencyInjection\Compiler\DbalTracingPass;
1010
use Sentry\SentryBundle\DependencyInjection\Compiler\HttpClientTracingPass;
11+
use Sentry\SentryBundle\DependencyInjection\Compiler\SentryBufferFlushPass;
1112
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
1213
use Symfony\Component\DependencyInjection\ContainerBuilder;
1314
use Symfony\Component\HttpKernel\Bundle\Bundle;
@@ -26,5 +27,6 @@ public function build(ContainerBuilder $container): void
2627
$container->addCompilerPass(new CacheTracingPass());
2728
$container->addCompilerPass(new HttpClientTracingPass());
2829
$container->addCompilerPass(new AddLoginListenerTagPass());
30+
$container->addCompilerPass(new SentryBufferFlushPass());
2931
}
3032
}

0 commit comments

Comments
 (0)