diff --git a/composer.json b/composer.json index d5efd789..8233eac3 100644 --- a/composer.json +++ b/composer.json @@ -49,7 +49,8 @@ "symfony/security-bundle": "^6.4|^7.0", "symfony/translation": "^6.4|^7.0", "symfony/twig-bundle": "^6.4|^7.0", - "symplify/easy-coding-standard": "^11.3" + "symplify/easy-coding-standard": "^11.3", + "symfony/monolog-bundle": "^3.10" }, "replace": { "yokai/batch": "self.version", diff --git a/src/batch-symfony-framework/docs/getting-started.md b/src/batch-symfony-framework/docs/getting-started.md index 593fc723..026e58df 100644 --- a/src/batch-symfony-framework/docs/getting-started.md +++ b/src/batch-symfony-framework/docs/getting-started.md @@ -104,6 +104,19 @@ The job launcher that will be injected depends on the packages you have installe - if `yokai/batch-symfony-console` is installed, you will receive a `Yokai\Batch\Bridge\Symfony\Console\RunCommandJobLauncher` - otherwise you will receive a `Yokai\Batch\Launcher\SimpleJobLauncher` + +## Define a custom BatchLogger +In a symfony project, a monolog handler could be declared as of: +```yaml +# config/packages/monolog.yaml +monolog: + handlers: + batch: + type: service + id: service.to.be.defined +``` + + ## On the same subject - [What is a job execution storage ?](https://github.com/yokai-php/batch/blob/0.x/docs/domain/job-execution-storage.md) diff --git a/src/batch-symfony-framework/src/DependencyInjection/YokaiBatchExtension.php b/src/batch-symfony-framework/src/DependencyInjection/YokaiBatchExtension.php index 7f269e1b..f42a0268 100644 --- a/src/batch-symfony-framework/src/DependencyInjection/YokaiBatchExtension.php +++ b/src/batch-symfony-framework/src/DependencyInjection/YokaiBatchExtension.php @@ -5,6 +5,7 @@ namespace Yokai\Batch\Bridge\Symfony\Framework\DependencyInjection; use Composer\InstalledVersions; +use Psr\Log\LoggerInterface; use Sonata\AdminBundle\Templating\TemplateRegistryInterface; use Symfony\Component\Config\FileLocator; use Symfony\Component\Config\Loader as ConfigLoader; @@ -22,6 +23,7 @@ use Yokai\Batch\Bridge\Symfony\Framework\UserInterface\Templating\SonataAdminTemplating; use Yokai\Batch\Bridge\Symfony\Framework\UserInterface\Templating\TemplatingInterface; use Yokai\Batch\Launcher\JobLauncherInterface; +use Yokai\Batch\Logger\BatchLogger; use Yokai\Batch\Storage\FilesystemJobExecutionStorage; use Yokai\Batch\Storage\JobExecutionStorageInterface; use Yokai\Batch\Storage\ListableJobExecutionStorageInterface; @@ -71,6 +73,8 @@ public function load(array $configs, ContainerBuilder $container): void JobLauncherInterface::class, \array_keys(\array_filter($launchers))[0] ?? 'yokai_batch.job_launcher.simple' ); + $container->registerAliasForArgument('yokai_batch.logger', LoggerInterface::class, 'yokaiBatchLogger'); + dump($container->getAliases()); } private function installed(string $package): bool diff --git a/src/batch-symfony-framework/src/Resources/services/global/logger.xml b/src/batch-symfony-framework/src/Resources/services/global/logger.xml new file mode 100644 index 00000000..c15d5235 --- /dev/null +++ b/src/batch-symfony-framework/src/Resources/services/global/logger.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + diff --git a/src/batch/src/Logger/BatchLogger.php b/src/batch/src/Logger/BatchLogger.php new file mode 100644 index 00000000..474f0559 --- /dev/null +++ b/src/batch/src/Logger/BatchLogger.php @@ -0,0 +1,48 @@ +batchLogger = $event->getExecution()->getLogger(); + } + + /** + * Forget the logger + */ + public function onPostExecute(PostExecuteEvent $event): void + { + $this->batchLogger = null; + } + + /** + * Log with the batchLogger defined in the PreExecuteEvent or with nullLogger if nothing remembered + * + * @param array $context + * @throws InvalidArgumentException + */ + public function log($level, Stringable|string $message, array $context = []): void + { + ($this->batchLogger ?? new NullLogger())->log($level, $message, $context); + } +} diff --git a/src/batch/tests/Logger/BatchLoggerTest.php b/src/batch/tests/Logger/BatchLoggerTest.php new file mode 100644 index 00000000..14743972 --- /dev/null +++ b/src/batch/tests/Logger/BatchLoggerTest.php @@ -0,0 +1,40 @@ +addListener(PreExecuteEvent::class, [$logger, 'onPreExecute']); + $dispatcher->addListener(PostExecuteEvent::class, [$logger, 'onPostExecute']); + + $execution = JobExecution::createRoot('123', 'test.job_executor'); + + $logger->log('info', 'before'); + $preExecuteEvent = new PreExecuteEvent($execution); + $dispatcher->dispatch($preExecuteEvent); + + $logger->log('info', 'between'); + + $postExecuteEvent = new PostExecuteEvent($execution); + $dispatcher->dispatch($postExecuteEvent); + $logger->log('info', 'after'); + + self::assertStringNotContainsString('before', $execution->getLogs()->__toString()); + self::assertStringContainsString('between', $execution->getLogs()->__toString()); + self::assertStringNotContainsString('after', $execution->getLogs()->__toString()); + } +} diff --git a/tests/symfony/src/Job/Country/CountryJob.php b/tests/symfony/src/Job/Country/CountryJob.php index 71870b65..2f349b85 100644 --- a/tests/symfony/src/Job/Country/CountryJob.php +++ b/tests/symfony/src/Job/Country/CountryJob.php @@ -4,6 +4,7 @@ namespace Yokai\Batch\Sources\Tests\Symfony\App\Job\Country; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\KernelInterface; use Yokai\Batch\Bridge\OpenSpout\Writer\FlatFileWriter; use Yokai\Batch\Bridge\Symfony\Framework\JobWithStaticNameInterface; @@ -56,14 +57,18 @@ final class CountryJob extends AbstractDecoratedJob implements private ItemWriterInterface $writer; private array $countries = []; private bool $flushed = false; + private LoggerInterface $yokaiBatchLogger; public static function getJobName(): string { return 'country'; } - public function __construct(JobExecutionStorageInterface $executionStorage, KernelInterface $kernel) - { + public function __construct( + JobExecutionStorageInterface $executionStorage, + KernelInterface $kernel, + LoggerInterface $yokaiBatchLogger + ) { $writePath = fn(string $format) => new StaticValueParameterAccessor( ARTIFACT_DIR . '/symfony/country/countries.' . $format ); @@ -81,6 +86,7 @@ public function __construct(JobExecutionStorageInterface $executionStorage, Kern new FlatFileWriter($writePath('csv'), null, null, $headers), new JsonLinesWriter($writePath('jsonl')), ]); + $this->yokaiBatchLogger = $yokaiBatchLogger; parent::__construct( new ItemJob( @@ -95,6 +101,8 @@ public function __construct(JobExecutionStorageInterface $executionStorage, Kern public function process(mixed $item): array { + $this->yokaiBatchLogger->log('info', 'log process'); + return ['iso2' => $item['code'], $item['_key'] => $item['value']]; } diff --git a/tests/symfony/tests/CountryJobSet.php b/tests/symfony/tests/CountryJobSet.php index 52eb49c7..3bfee185 100644 --- a/tests/symfony/tests/CountryJobSet.php +++ b/tests/symfony/tests/CountryJobSet.php @@ -74,6 +74,7 @@ static function (JobExecution $execution) { '{"iso2":"GB","iso3":"GBR","name":"United Kingdom","continent":"EU","currency":"GBP","phone":"44"}', $jsonl ); + Assert::assertStringContainsString('log process', $execution->getLogs()->__toString()); }, ]; }