diff --git a/webapp/config/packages/monolog.yaml b/webapp/config/packages/monolog.yaml index 1c8b8d33b2..7cf112285a 100644 --- a/webapp/config/packages/monolog.yaml +++ b/webapp/config/packages/monolog.yaml @@ -1,15 +1,3 @@ -monolog: - # Set up logger for the event feed importer. - # key, to make sure the logs don't also appear there. - channels: - - event-feed-importer - handlers: - event-feed-importer: - level: info - type: stream - path: "%kernel.logs_dir%/event-feed-importer.log" - channels: ["event-feed-importer"] - when@dev: monolog: handlers: @@ -31,10 +19,6 @@ when@dev: process_psr_3_messages: false channels: ["!event", "!doctrine", "!console"] - # In dev mode, also log debug messages - event-feed-importer: - level: debug - when@test: monolog: handlers: diff --git a/webapp/src/DependencyInjection/Compiler/RemoveEventFeedImporterChannelFromLogs.php b/webapp/src/DependencyInjection/Compiler/RemoveEventFeedImporterChannelFromLogs.php deleted file mode 100644 index 9bf4fdd5f4..0000000000 --- a/webapp/src/DependencyInjection/Compiler/RemoveEventFeedImporterChannelFromLogs.php +++ /dev/null @@ -1,19 +0,0 @@ -getDefinition('monolog.logger.event-feed-importer') - ->removeMethodCall('pushHandler') - ->addMethodCall('pushHandler', [new Reference('monolog.handler.event_feed_importer')]); - } -} diff --git a/webapp/src/Kernel.php b/webapp/src/Kernel.php index f420b0f457..febc424c2a 100644 --- a/webapp/src/Kernel.php +++ b/webapp/src/Kernel.php @@ -2,7 +2,6 @@ namespace App; -use App\DependencyInjection\Compiler\RemoveEventFeedImporterChannelFromLogs; use App\DependencyInjection\Compiler\SetDocLinksPass; use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -20,6 +19,5 @@ public function getProjectDir(): string protected function build(ContainerBuilder $container): void { $container->addCompilerPass(new SetDocLinksPass()); - $container->addCompilerPass(new RemoveEventFeedImporterChannelFromLogs()); } } diff --git a/webapp/src/Service/ExternalContestSourceService.php b/webapp/src/Service/ExternalContestSourceService.php index 709d3ea3c8..7970b6b134 100644 --- a/webapp/src/Service/ExternalContestSourceService.php +++ b/webapp/src/Service/ExternalContestSourceService.php @@ -44,8 +44,13 @@ use Exception; use InvalidArgumentException; use LogicException; +use Monolog\Handler\StreamHandler; +use Monolog\Level; +use Monolog\Logger; +use Monolog\Processor\ProcessorInterface; use Psr\Log\LoggerInterface; use Symfony\Component\DependencyInjection\Attribute\Autowire; +use Symfony\Component\DependencyInjection\Attribute\AutowireIterator; use Symfony\Component\HttpClient\Exception\TransportException; use Symfony\Component\HttpFoundation\File\UploadedFile; use Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException; @@ -58,6 +63,7 @@ use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; +use Traversable; use ZipArchive; class ExternalContestSourceService @@ -66,6 +72,8 @@ class ExternalContestSourceService protected ?ExternalContestSource $source = null; + protected LoggerInterface $logger; + protected bool $contestLoaded = false; protected ?ContestData $cachedContestData = null; protected ?ApiInfo $cachedApiInfoData = null; @@ -100,19 +108,28 @@ class ExternalContestSourceService 'submission' => [], ]; + /** + * @param Traversable $logProcessors + */ public function __construct( HttpClientInterface $httpClient, protected readonly DOMJudgeService $dj, protected readonly EntityManagerInterface $em, - #[Autowire(service: 'monolog.logger.event-feed-importer')] - protected readonly LoggerInterface $logger, protected readonly ConfigurationService $config, protected readonly EventLogService $eventLog, protected readonly SubmissionService $submissionService, protected readonly ScoreboardService $scoreboardService, protected readonly SerializerInterface&DenormalizerInterface&NormalizerInterface $serializer, + #[AutowireIterator(tag: 'monolog.processor')] + protected readonly Traversable $logProcessors, + #[Autowire(service: 'monolog.processor.psr_log_message')] + protected readonly ProcessorInterface $psrLogMessageProcessor, + #[Autowire(param: 'kernel.logs_dir')] + protected readonly string $logDir, + #[Autowire(param: 'kernel.environment')] + protected readonly string $env, #[Autowire('%domjudge.version%')] - string $domjudgeVersion + string $domjudgeVersion, ) { $clientOptions = [ 'headers' => [ @@ -269,6 +286,8 @@ public function getLastReadEventId(): ?string */ public function import(bool $fromStart, array $eventsToSkip, ?callable $progressReporter = null): bool { + $this->configureLogger(); + // We need the verdicts to validate judgement-types. $this->verdicts = $this->config->getVerdicts(['final', 'external']); @@ -2087,4 +2106,19 @@ protected function removeWarning(EventType $eventType, ?string $entityId, string $this->em->flush(); } } + + protected function configureLogger(): void + { + // Configure a logger to use a file per contest. + // For this we need to create our own logger. + // This code is based on what Symfony does with their default loggers. + $name = sprintf('event-feed-importer-%s', $this->getSourceContestId()); + $logFile = sprintf('%s/%s.log', $this->logDir, $name); + $handler = new StreamHandler( + $logFile, + $this->env === 'dev' ? Level::Debug : Level::Info, + ); + $handler->pushProcessor($this->psrLogMessageProcessor); + $this->logger = new Logger($name, [$handler], iterator_to_array($this->logProcessors)); + } }