Skip to content

Commit fb76baf

Browse files
committed
add logging to data tasks
1 parent c210332 commit fb76baf

File tree

5 files changed

+182
-10
lines changed

5 files changed

+182
-10
lines changed

src/Pipeline/Pipe/ArrayPipe.php

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Exception;
88
use Liquetsoft\Fias\Component\Pipeline\State\State;
9+
use Liquetsoft\Fias\Component\Pipeline\Task\LoggableTask;
910
use Liquetsoft\Fias\Component\Pipeline\Task\Task;
1011
use Liquetsoft\Fias\Component\Exception\PipeException;
1112
use InvalidArgumentException;
@@ -101,12 +102,13 @@ protected function proceedStart(State $state): void
101102
*/
102103
protected function proceedTask(State $state, Task $task): void
103104
{
104-
$taskName = get_class($task);
105+
$taskName = $this->getTaskId($task);
105106
$this->log(
106107
LogLevel::INFO,
107108
"Start '{$taskName}' task.",
108109
['task' => $taskName]
109110
);
111+
$this->injectLoggerToTask($task);
110112
$task->run($state);
111113
$this->log(
112114
LogLevel::INFO,
@@ -126,7 +128,7 @@ protected function proceedTask(State $state, Task $task): void
126128
*/
127129
protected function proceedException(State $state, Task $task, Throwable $e): void
128130
{
129-
$taskName = get_class($task);
131+
$taskName = $this->getTaskId($task);
130132
$message = "Error while running {$taskName} task: {$e->getMessage()}";
131133

132134
$this->log(LogLevel::ERROR, $message, [
@@ -177,12 +179,43 @@ protected function proceedComplete(State $state): void
177179
protected function log(string $level, string $message, array $context = []): void
178180
{
179181
if ($this->logger) {
180-
$context['pipeline'] = get_class($this);
181-
$context['pipeline_id'] = $this->id;
182-
$this->logger->log($level, "Pipeline {$this->id}. {$message}", $context);
182+
$context = $this->createLoggerContext($context);
183+
$this->logger->log($level, $message, $context);
183184
}
184185
}
185186

187+
/**
188+
* Добавляет логгер в операцию, если операция поддерживает логгирование.
189+
*
190+
* @param Task $task
191+
*/
192+
protected function injectLoggerToTask(Task $task): void
193+
{
194+
if ($task instanceof LoggableTask && $this->logger) {
195+
$task->injectLogger(
196+
$this->logger,
197+
$this->createLoggerContext(['task' => $this->getTaskId($task)])
198+
);
199+
}
200+
}
201+
202+
/**
203+
* Возвращает дефолтный контекст логгирования.
204+
*
205+
* @param array $currentContext
206+
*
207+
* @return array
208+
*/
209+
protected function createLoggerContext(array $currentContext = []): array
210+
{
211+
$defaultContext = [
212+
'pipeline_class' => get_class($this),
213+
'pipeline_id' => $this->id,
214+
];
215+
216+
return array_merge($defaultContext, $currentContext);
217+
}
218+
186219
/**
187220
* Проверяет все объекты массива, чтобы они были валидными задачами и возвращает его.
188221
*
@@ -207,4 +240,16 @@ protected function checkAndReturnTaskArray(iterable $tasks): array
207240

208241
return $return;
209242
}
243+
244+
/**
245+
* Возвращает идентификатор операции.
246+
*
247+
* @param Task $task
248+
*
249+
* @return string
250+
*/
251+
protected function getTaskId(Task $task): string
252+
{
253+
return get_class($task);
254+
}
210255
}

src/Pipeline/Task/DataAbstractTask.php

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Liquetsoft\Fias\Component\Pipeline\State\State;
1313
use Liquetsoft\Fias\Component\EntityDescriptor\EntityDescriptor;
1414
use Liquetsoft\Fias\Component\Exception\TaskException;
15+
use Psr\Log\LogLevel;
1516
use Symfony\Component\Serializer\SerializerInterface;
1617
use SplFileInfo;
1718
use RecursiveDirectoryIterator;
@@ -20,8 +21,10 @@
2021
/**
2122
* Абстрактная задача, которая переносит данные из xml в хранилище данных.
2223
*/
23-
abstract class DataAbstractTask implements Task
24+
abstract class DataAbstractTask implements Task, LoggableTask
2425
{
26+
use LoggableTaskTrait;
27+
2528
/**
2629
* @var EntityManager
2730
*/
@@ -129,17 +132,36 @@ protected function processFile(SplFileInfo $fileInfo): void
129132
*/
130133
protected function processDataFromFile(SplFileInfo $fileInfo, string $xpath, string $entityClass): void
131134
{
135+
$this->log(
136+
LogLevel::INFO,
137+
"Start processing '{$fileInfo->getRealPath()}' file for '{$entityClass}' entity.",
138+
[
139+
'entity' => $entityClass,
140+
'path' => $fileInfo->getRealPath(),
141+
]
142+
);
143+
144+
$total = 0;
132145
$this->xmlReader->open($fileInfo, $xpath);
133146
$this->storage->start();
134-
135147
try {
136148
foreach ($this->xmlReader as $xml) {
137149
$this->processItem($this->deserializeXmlStringToObject($xml, $entityClass));
150+
++$total;
138151
}
139152
} finally {
140153
$this->storage->stop();
141154
$this->xmlReader->close();
142155
}
156+
157+
$this->log(
158+
LogLevel::INFO,
159+
"Complete processing '{$fileInfo->getRealPath()}' file for '{$entityClass}' entity. {$total} items processed.",
160+
[
161+
'entity' => $entityClass,
162+
'path' => $fileInfo->getRealPath(),
163+
]
164+
);
143165
}
144166

145167
/**

src/Pipeline/Task/LoggableTask.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Liquetsoft\Fias\Component\Pipeline\Task;
6+
7+
use Psr\Log\LoggerInterface;
8+
9+
/**
10+
* Интерфейс для объекта операции, которая может логгировать свой действия.
11+
*/
12+
interface LoggableTask
13+
{
14+
/**
15+
* Добавляет ссылку на объект логгера в объект операции.
16+
*
17+
* @param LoggerInterface $logger
18+
* @param array $defaultContext
19+
*/
20+
public function injectLogger(LoggerInterface $logger, array $defaultContext = []): void;
21+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Liquetsoft\Fias\Component\Pipeline\Task;
6+
7+
use Psr\Log\LoggerInterface;
8+
9+
/**
10+
* Трейт в пару к LoggableTask интерфейсу.
11+
*/
12+
trait LoggableTaskTrait
13+
{
14+
/**
15+
* @var LoggerInterface|null
16+
*/
17+
protected $logger;
18+
19+
/**
20+
* @var array
21+
*/
22+
protected $defaultContext = [];
23+
24+
/**
25+
* Добавляет ссылку на объект логгера в объект операции.
26+
*
27+
* @param LoggerInterface $logger
28+
* @param array $defaultContext
29+
*/
30+
public function injectLogger(LoggerInterface $logger, array $defaultContext = []): void
31+
{
32+
$this->logger = $logger;
33+
$this->defaultContext = $defaultContext;
34+
}
35+
36+
/**
37+
* Логгирует сообщение.
38+
*
39+
* @param string $logLevel
40+
* @param string $message
41+
* @param array $context
42+
*/
43+
public function log(string $logLevel, string $message, array $context = []): void
44+
{
45+
if ($this->logger) {
46+
$context = array_merge($this->defaultContext, $context);
47+
$this->logger->log($logLevel, $message, $context);
48+
}
49+
}
50+
}

tests/src/Pipeline/Pipe/ArrayPipeTest.php

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Liquetsoft\Fias\Component\Pipeline\Pipe\ArrayPipe;
88
use Liquetsoft\Fias\Component\Pipeline\State\State;
9+
use Liquetsoft\Fias\Component\Pipeline\Task\LoggableTask;
910
use Liquetsoft\Fias\Component\Pipeline\Task\Task;
1011
use Liquetsoft\Fias\Component\Tests\BaseCase;
1112
use Liquetsoft\Fias\Component\Exception\PipeException;
@@ -124,12 +125,45 @@ public function testRunException()
124125
public function testLogger()
125126
{
126127
$state = $this->getMockBuilder(State::class)->getMock();
127-
$state->expects($this->once())->method('complete');
128-
129128
$task = $this->getMockBuilder(Task::class)->getMock();
130129

131130
$logger = $this->getMockBuilder(LoggerInterface::class)->getMock();
132-
$logger->expects($this->atLeastOnce())->method('log');
131+
$logger->expects($this->atLeastOnce())
132+
->method('log')
133+
->with(
134+
$this->anything(),
135+
$this->anything(),
136+
$this->logicalAnd(
137+
$this->arrayHasKey('pipeline_class'),
138+
$this->arrayHasKey('pipeline_id')
139+
)
140+
)
141+
;
142+
143+
$pipe = new ArrayPipe([$task], null, $logger);
144+
$pipe->run($state);
145+
}
146+
147+
/**
148+
* Проверяет, что очередь передаст объект лога в задачу, если требуется.
149+
*/
150+
public function testLoggableTaskLoggerInjected()
151+
{
152+
$state = $this->getMockBuilder(State::class)->getMock();
153+
$logger = $this->getMockBuilder(LoggerInterface::class)->getMock();
154+
155+
$task = $this->getMockBuilder([Task::class, LoggableTask::class])->getMock();
156+
$task->expects($this->once())
157+
->method('injectLogger')
158+
->with(
159+
$this->identicalTo($logger),
160+
$this->logicalAnd(
161+
$this->arrayHasKey('pipeline_class'),
162+
$this->arrayHasKey('pipeline_id'),
163+
$this->arrayHasKey('task')
164+
)
165+
)
166+
;
133167

134168
$pipe = new ArrayPipe([$task], null, $logger);
135169
$pipe->run($state);

0 commit comments

Comments
 (0)