44
44
use Exception ;
45
45
use InvalidArgumentException ;
46
46
use LogicException ;
47
+ use Monolog \Handler \StreamHandler ;
48
+ use Monolog \Level ;
49
+ use Monolog \Logger ;
50
+ use Monolog \Processor \ProcessorInterface ;
47
51
use Psr \Log \LoggerInterface ;
48
52
use Symfony \Component \DependencyInjection \Attribute \Autowire ;
53
+ use Symfony \Component \DependencyInjection \Attribute \AutowireIterator ;
49
54
use Symfony \Component \HttpClient \Exception \TransportException ;
50
55
use Symfony \Component \HttpFoundation \File \UploadedFile ;
51
56
use Symfony \Component \PropertyAccess \Exception \UnexpectedTypeException ;
58
63
use Symfony \Contracts \HttpClient \Exception \HttpExceptionInterface ;
59
64
use Symfony \Contracts \HttpClient \Exception \TransportExceptionInterface ;
60
65
use Symfony \Contracts \HttpClient \HttpClientInterface ;
66
+ use Traversable ;
61
67
use ZipArchive ;
62
68
63
69
class ExternalContestSourceService
@@ -66,6 +72,8 @@ class ExternalContestSourceService
66
72
67
73
protected ?ExternalContestSource $ source = null ;
68
74
75
+ protected LoggerInterface $ logger ;
76
+
69
77
protected bool $ contestLoaded = false ;
70
78
protected ?ContestData $ cachedContestData = null ;
71
79
protected ?ApiInfo $ cachedApiInfoData = null ;
@@ -100,19 +108,28 @@ class ExternalContestSourceService
100
108
'submission ' => [],
101
109
];
102
110
111
+ /**
112
+ * @param Traversable<ProcessorInterface> $logProcessors
113
+ */
103
114
public function __construct (
104
115
HttpClientInterface $ httpClient ,
105
116
protected readonly DOMJudgeService $ dj ,
106
117
protected readonly EntityManagerInterface $ em ,
107
- #[Autowire(service: 'monolog.logger.event-feed-importer ' )]
108
- protected readonly LoggerInterface $ logger ,
109
118
protected readonly ConfigurationService $ config ,
110
119
protected readonly EventLogService $ eventLog ,
111
120
protected readonly SubmissionService $ submissionService ,
112
121
protected readonly ScoreboardService $ scoreboardService ,
113
122
protected readonly SerializerInterface &DenormalizerInterface &NormalizerInterface $ serializer ,
123
+ #[AutowireIterator(tag: 'monolog.processor ' )]
124
+ protected readonly Traversable $ logProcessors ,
125
+ #[Autowire(service: 'monolog.processor.psr_log_message ' )]
126
+ protected readonly ProcessorInterface $ psrLogMessageProcessor ,
127
+ #[Autowire(param: 'kernel.logs_dir ' )]
128
+ protected readonly string $ logDir ,
129
+ #[Autowire(param: 'kernel.environment ' )]
130
+ protected readonly string $ env ,
114
131
#[Autowire('%domjudge.version% ' )]
115
- string $ domjudgeVersion
132
+ string $ domjudgeVersion,
116
133
) {
117
134
$ clientOptions = [
118
135
'headers ' => [
@@ -269,6 +286,8 @@ public function getLastReadEventId(): ?string
269
286
*/
270
287
public function import (bool $ fromStart , array $ eventsToSkip , ?callable $ progressReporter = null ): bool
271
288
{
289
+ $ this ->configureLogger ();
290
+
272
291
// We need the verdicts to validate judgement-types.
273
292
$ this ->verdicts = $ this ->config ->getVerdicts (['final ' , 'external ' ]);
274
293
@@ -2087,4 +2106,19 @@ protected function removeWarning(EventType $eventType, ?string $entityId, string
2087
2106
$ this ->em ->flush ();
2088
2107
}
2089
2108
}
2109
+
2110
+ protected function configureLogger (): void
2111
+ {
2112
+ // Configure a logger to use a file per contest.
2113
+ // For this we need to create our own logger.
2114
+ // This code is based on what Symfony does with their default loggers.
2115
+ $ name = sprintf ('event-feed-importer-%s ' , $ this ->getSourceContestId ());
2116
+ $ logFile = sprintf ('%s/%s.log ' , $ this ->logDir , $ name );
2117
+ $ handler = new StreamHandler (
2118
+ $ logFile ,
2119
+ $ this ->env === 'dev ' ? Level::Debug : Level::Info,
2120
+ );
2121
+ $ handler ->pushProcessor ($ this ->psrLogMessageProcessor );
2122
+ $ this ->logger = new Logger ($ name , [$ handler ], iterator_to_array ($ this ->logProcessors ));
2123
+ }
2090
2124
}
0 commit comments