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