Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ jobs:
php: ['8.4']
sf_version: ['8.0.*']
include:
- php: '8.0'
sf_version: '5.4.*'
- php: '8.1'
- php: '8.2'
sf_version: '6.4.*'
- php: '8.2'
sf_version: '7.4.*'
Expand Down Expand Up @@ -49,7 +47,7 @@ jobs:
- name: Set up PHP
uses: shivammathur/setup-php@2.7.0
with:
php-version: 8.0
php-version: 8.2
coverage: pcov

- name: Checkout code
Expand All @@ -60,5 +58,5 @@ jobs:

- name: Run tests
env:
PHP_VERSION: '8.0'
PHP_VERSION: '8.2'
run: ./vendor/bin/phpunit -v --coverage-text
2 changes: 1 addition & 1 deletion .github/workflows/static.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
- name: Set up PHP
uses: shivammathur/setup-php@2.7.0
with:
php-version: 8.0
php-version: 8.2

- name: Download dependencies
run: composer update --no-interaction --prefer-dist --no-progress --no-suggest --dev
Expand Down
21 changes: 14 additions & 7 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@
}
},
"require": {
"php": ">=8.0",
"bref/bref": "^1.2|^2.0|^3.0",
"php": ">=8.2",
"bref/bref": "^2.0|^3",
"bref/monolog-bridge": "^1.0",
"symfony/dependency-injection": "^5.4|^6.0|^7.0|^8.0",
"symfony/filesystem": "^5.4|^6.0|^7.0|^8.0",
"symfony/http-kernel": "^5.4|^6.0|^7.0|^8.0",
"symfony/psr-http-message-bridge": "^2.1|^6.4|^7.0|^8.0",
Expand All @@ -34,11 +35,17 @@
"mnapoli/hard-mode": "^0.3.0",
"phpstan/phpstan": "^1.3",
"phpunit/phpunit": "^8.5.22",
"symfony/config": "^5.4|^6.0|^7.0",
"symfony/dependency-injection": "^5.4|^6.0|^7.0",
"symfony/framework-bundle": "^5.4|^6.0|^7.0",
"symfony/phpunit-bridge": "^6.0|^7.0",
"symfony/process": "^5.4|^6.0|^7.0"
"symfony/config": "^5.4|^6.0|^7.0|^8.0",
"symfony/framework-bundle": "^5.4|^6.0|^7.0|^8.0",
"symfony/phpunit-bridge": "^6.0|^7.0|^8.0",
"symfony/process": "^5.4|^6.0|^7.0|^8.0"
},
"extra": {
"symfony": {
"bundles": {
"Bref\\SymfonyBridge\\BrefBundle": ["all"]
}
}
},
"config": {
"sort-packages": true,
Expand Down
14 changes: 14 additions & 0 deletions src/BrefBundle.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php declare(strict_types=1);

namespace Bref\SymfonyBridge;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;

class BrefBundle extends Bundle
{
public function build(ContainerBuilder $container): void
{
$container->addCompilerPass(new CloudWatchMonologFormatterPass);
}
}
41 changes: 41 additions & 0 deletions src/CloudWatchMonologFormatterPass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php declare(strict_types=1);

namespace Bref\SymfonyBridge;

use Bref\Monolog\CloudWatchFormatter;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

/**
* Automatically sets the CloudWatch-optimized formatter on all Monolog handlers.
*
* Handlers that already have an explicit formatter configured are left unchanged,
* allowing users to override per-handler in their monolog.yaml configuration.
*/
class CloudWatchMonologFormatterPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container): void
{
if (! $container->has('bref.cloudwatch_formatter')) {
$container->register('bref.cloudwatch_formatter', CloudWatchFormatter::class);
}

$formatterRef = new Reference('bref.cloudwatch_formatter');

foreach ($container->getDefinitions() as $id => $definition) {
if (! str_starts_with($id, 'monolog.handler.')) {
continue;
}

// Don't override formatter if explicitly set by the user
foreach ($definition->getMethodCalls() as [$method]) {
if ($method === 'setFormatter') {
continue 2;
}
}

$definition->addMethodCall('setFormatter', [$formatterRef]);
}
}
}
76 changes: 76 additions & 0 deletions tests/Unit/CloudWatchMonologFormatterPassTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php declare(strict_types=1);

namespace Bref\SymfonyBridge\Test\Unit;

use Bref\Monolog\CloudWatchFormatter;
use Bref\SymfonyBridge\CloudWatchMonologFormatterPass;
use Monolog\Handler\StreamHandler;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

class CloudWatchMonologFormatterPassTest extends TestCase
{
public function testSetsFormatterOnMonologHandlers()
{
$container = new ContainerBuilder;
$container->register('monolog.handler.main', StreamHandler::class);
$container->register('monolog.handler.console', StreamHandler::class);

$pass = new CloudWatchMonologFormatterPass;
$pass->process($container);

self::assertTrue($container->has('bref.cloudwatch_formatter'));
self::assertSame(CloudWatchFormatter::class, $container->getDefinition('bref.cloudwatch_formatter')->getClass());

// Both handlers should have the formatter set
$mainCalls = $container->getDefinition('monolog.handler.main')->getMethodCalls();
self::assertCount(1, $mainCalls);
self::assertSame('setFormatter', $mainCalls[0][0]);
self::assertInstanceOf(Reference::class, $mainCalls[0][1][0]);
self::assertSame('bref.cloudwatch_formatter', (string) $mainCalls[0][1][0]);

$consoleCalls = $container->getDefinition('monolog.handler.console')->getMethodCalls();
self::assertCount(1, $consoleCalls);
self::assertSame('setFormatter', $consoleCalls[0][0]);
}

public function testDoesNotOverrideExplicitFormatter()
{
$container = new ContainerBuilder;

$handler = $container->register('monolog.handler.main', StreamHandler::class);
$handler->addMethodCall('setFormatter', [new Reference('my_custom_formatter')]);

$pass = new CloudWatchMonologFormatterPass;
$pass->process($container);

// Should still have only the original formatter
$calls = $container->getDefinition('monolog.handler.main')->getMethodCalls();
self::assertCount(1, $calls);
self::assertSame('my_custom_formatter', (string) $calls[0][1][0]);
}

public function testDoesNotTouchNonMonologServices()
{
$container = new ContainerBuilder;
$container->register('app.my_service', StreamHandler::class);

$pass = new CloudWatchMonologFormatterPass;
$pass->process($container);

self::assertEmpty($container->getDefinition('app.my_service')->getMethodCalls());
}

public function testDoesNothingWhenNoMonologHandlersExist()
{
$container = new ContainerBuilder;
$container->register('app.my_service', StreamHandler::class);

$pass = new CloudWatchMonologFormatterPass;
$pass->process($container);

// Formatter service should still be registered (it's harmless)
self::assertTrue($container->has('bref.cloudwatch_formatter'));
}
}