Add step type, step key, and updated timestamp to run logs
[MAILPOET-5568]
This commit is contained in:
@ -5,6 +5,7 @@ namespace MailPoet\Automation\Engine\Control;
|
|||||||
use Exception;
|
use Exception;
|
||||||
use MailPoet\Automation\Engine\Data\Automation;
|
use MailPoet\Automation\Engine\Data\Automation;
|
||||||
use MailPoet\Automation\Engine\Data\AutomationRun;
|
use MailPoet\Automation\Engine\Data\AutomationRun;
|
||||||
|
use MailPoet\Automation\Engine\Data\AutomationRunLog;
|
||||||
use MailPoet\Automation\Engine\Data\StepRunArgs;
|
use MailPoet\Automation\Engine\Data\StepRunArgs;
|
||||||
use MailPoet\Automation\Engine\Data\StepValidationArgs;
|
use MailPoet\Automation\Engine\Data\StepValidationArgs;
|
||||||
use MailPoet\Automation\Engine\Data\SubjectEntry;
|
use MailPoet\Automation\Engine\Data\SubjectEntry;
|
||||||
@ -86,7 +87,7 @@ class StepHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$logger = $this->stepRunLoggerFactory->createLogger($runId, $stepId);
|
$logger = $this->stepRunLoggerFactory->createLogger($runId, $stepId, AutomationRunLog::TYPE_ACTION);
|
||||||
$logger->logStart();
|
$logger->logStart();
|
||||||
try {
|
try {
|
||||||
$this->handleStep($runId, $stepId, $runNumber);
|
$this->handleStep($runId, $stepId, $runNumber);
|
||||||
|
@ -25,16 +25,21 @@ class StepRunLogger {
|
|||||||
/** @var AutomationRunLog|null */
|
/** @var AutomationRunLog|null */
|
||||||
private $log;
|
private $log;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $stepType;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
AutomationRunLogStorage $automationRunLogStorage,
|
AutomationRunLogStorage $automationRunLogStorage,
|
||||||
Hooks $hooks,
|
Hooks $hooks,
|
||||||
int $runId,
|
int $runId,
|
||||||
string $stepId
|
string $stepId,
|
||||||
|
string $stepType
|
||||||
) {
|
) {
|
||||||
$this->automationRunLogStorage = $automationRunLogStorage;
|
$this->automationRunLogStorage = $automationRunLogStorage;
|
||||||
$this->hooks = $hooks;
|
$this->hooks = $hooks;
|
||||||
$this->runId = $runId;
|
$this->runId = $runId;
|
||||||
$this->stepId = $stepId;
|
$this->stepId = $stepId;
|
||||||
|
$this->stepType = $stepType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function logStart(): void {
|
public function logStart(): void {
|
||||||
@ -44,7 +49,7 @@ class StepRunLogger {
|
|||||||
public function logSuccess(): void {
|
public function logSuccess(): void {
|
||||||
$log = $this->getLog();
|
$log = $this->getLog();
|
||||||
$log->setStatus(AutomationRunLog::STATUS_COMPLETE);
|
$log->setStatus(AutomationRunLog::STATUS_COMPLETE);
|
||||||
$log->setCompletedAt(new DateTimeImmutable());
|
$log->setUpdatedAt(new DateTimeImmutable());
|
||||||
$this->triggerAfterRunHook($log);
|
$this->triggerAfterRunHook($log);
|
||||||
$this->automationRunLogStorage->updateAutomationRunLog($log);
|
$this->automationRunLogStorage->updateAutomationRunLog($log);
|
||||||
}
|
}
|
||||||
@ -53,7 +58,7 @@ class StepRunLogger {
|
|||||||
$log = $this->getLog();
|
$log = $this->getLog();
|
||||||
$log->setStatus(AutomationRunLog::STATUS_FAILED);
|
$log->setStatus(AutomationRunLog::STATUS_FAILED);
|
||||||
$log->setError($error);
|
$log->setError($error);
|
||||||
$log->setCompletedAt(new DateTimeImmutable());
|
$log->setUpdatedAt(new DateTimeImmutable());
|
||||||
$this->triggerAfterRunHook($log);
|
$this->triggerAfterRunHook($log);
|
||||||
$this->automationRunLogStorage->updateAutomationRunLog($log);
|
$this->automationRunLogStorage->updateAutomationRunLog($log);
|
||||||
}
|
}
|
||||||
@ -64,7 +69,7 @@ class StepRunLogger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->log) {
|
if (!$this->log) {
|
||||||
$log = new AutomationRunLog($this->runId, $this->stepId);
|
$log = new AutomationRunLog($this->runId, $this->stepId, $this->stepType);
|
||||||
$id = $this->automationRunLogStorage->createAutomationRunLog($log);
|
$id = $this->automationRunLogStorage->createAutomationRunLog($log);
|
||||||
$this->log = $this->automationRunLogStorage->getAutomationRunLog($id);
|
$this->log = $this->automationRunLogStorage->getAutomationRunLog($id);
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ class StepRunLoggerFactory {
|
|||||||
$this->hooks = $hooks;
|
$this->hooks = $hooks;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createLogger(int $runId, string $stepId): StepRunLogger {
|
public function createLogger(int $runId, string $stepId, string $stepType): StepRunLogger {
|
||||||
return new StepRunLogger($this->automationRunLogStorage, $this->hooks, $runId, $stepId);
|
return new StepRunLogger($this->automationRunLogStorage, $this->hooks, $runId, $stepId, $stepType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,11 @@ class AutomationRunLog {
|
|||||||
self::STATUS_FAILED,
|
self::STATUS_FAILED,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public const TYPE_ACTION = 'action';
|
||||||
|
public const TYPE_TRIGGER = 'trigger';
|
||||||
|
|
||||||
|
public const KEY_UNKNOWN = 'unknown';
|
||||||
|
|
||||||
/** @var int */
|
/** @var int */
|
||||||
private $id;
|
private $id;
|
||||||
|
|
||||||
@ -27,14 +32,20 @@ class AutomationRunLog {
|
|||||||
/** @var string */
|
/** @var string */
|
||||||
private $stepId;
|
private $stepId;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $stepType;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $stepKey;
|
||||||
|
|
||||||
/** @var string */
|
/** @var string */
|
||||||
private $status;
|
private $status;
|
||||||
|
|
||||||
/** @var DateTimeImmutable */
|
/** @var DateTimeImmutable */
|
||||||
private $startedAt;
|
private $startedAt;
|
||||||
|
|
||||||
/** @var DateTimeImmutable|null */
|
/** @var DateTimeImmutable */
|
||||||
private $completedAt;
|
private $updatedAt;
|
||||||
|
|
||||||
/** @var array */
|
/** @var array */
|
||||||
private $data = [];
|
private $data = [];
|
||||||
@ -45,12 +56,18 @@ class AutomationRunLog {
|
|||||||
public function __construct(
|
public function __construct(
|
||||||
int $automationRunId,
|
int $automationRunId,
|
||||||
string $stepId,
|
string $stepId,
|
||||||
|
string $stepType,
|
||||||
int $id = null
|
int $id = null
|
||||||
) {
|
) {
|
||||||
$this->automationRunId = $automationRunId;
|
$this->automationRunId = $automationRunId;
|
||||||
$this->stepId = $stepId;
|
$this->stepId = $stepId;
|
||||||
|
$this->stepType = $stepType;
|
||||||
|
$this->stepKey = self::KEY_UNKNOWN;
|
||||||
$this->status = self::STATUS_RUNNING;
|
$this->status = self::STATUS_RUNNING;
|
||||||
$this->startedAt = new DateTimeImmutable();
|
|
||||||
|
$now = new DateTimeImmutable();
|
||||||
|
$this->startedAt = $now;
|
||||||
|
$this->updatedAt = $now;
|
||||||
|
|
||||||
if ($id) {
|
if ($id) {
|
||||||
$this->id = $id;
|
$this->id = $id;
|
||||||
@ -69,6 +86,19 @@ class AutomationRunLog {
|
|||||||
return $this->stepId;
|
return $this->stepId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getStepType(): string {
|
||||||
|
return $this->stepType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStepKey(): string {
|
||||||
|
return $this->stepKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setStepKey(string $stepKey): void {
|
||||||
|
$this->stepKey = $stepKey;
|
||||||
|
$this->updatedAt = new DateTimeImmutable();
|
||||||
|
}
|
||||||
|
|
||||||
public function getStatus(): string {
|
public function getStatus(): string {
|
||||||
return $this->status;
|
return $this->status;
|
||||||
}
|
}
|
||||||
@ -78,18 +108,19 @@ class AutomationRunLog {
|
|||||||
throw new InvalidArgumentException("Invalid status '$status'.");
|
throw new InvalidArgumentException("Invalid status '$status'.");
|
||||||
}
|
}
|
||||||
$this->status = $status;
|
$this->status = $status;
|
||||||
|
$this->updatedAt = new DateTimeImmutable();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getStartedAt(): DateTimeImmutable {
|
public function getStartedAt(): DateTimeImmutable {
|
||||||
return $this->startedAt;
|
return $this->startedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCompletedAt(): ?DateTimeImmutable {
|
public function getUpdatedAt(): DateTimeImmutable {
|
||||||
return $this->completedAt;
|
return $this->updatedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setCompletedAt(DateTimeImmutable $completedAt): void {
|
public function setUpdatedAt(DateTimeImmutable $updatedAt): void {
|
||||||
$this->completedAt = $completedAt;
|
$this->updatedAt = $updatedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getData(): array {
|
public function getData(): array {
|
||||||
@ -102,6 +133,7 @@ class AutomationRunLog {
|
|||||||
throw new InvalidArgumentException("Invalid data provided for key '$key'. Only scalar values and arrays of scalar values are allowed.");
|
throw new InvalidArgumentException("Invalid data provided for key '$key'. Only scalar values and arrays of scalar values are allowed.");
|
||||||
}
|
}
|
||||||
$this->data[$key] = $value;
|
$this->data[$key] = $value;
|
||||||
|
$this->updatedAt = new DateTimeImmutable();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getError(): array {
|
public function getError(): array {
|
||||||
@ -110,13 +142,16 @@ class AutomationRunLog {
|
|||||||
|
|
||||||
public function toArray(): array {
|
public function toArray(): array {
|
||||||
return [
|
return [
|
||||||
|
'id' => $this->id,
|
||||||
'automation_run_id' => $this->automationRunId,
|
'automation_run_id' => $this->automationRunId,
|
||||||
'step_id' => $this->stepId,
|
'step_id' => $this->stepId,
|
||||||
|
'step_type' => $this->stepType,
|
||||||
|
'step_key' => $this->stepKey,
|
||||||
'status' => $this->status,
|
'status' => $this->status,
|
||||||
'started_at' => $this->startedAt->format(DateTimeImmutable::W3C),
|
'started_at' => $this->startedAt->format(DateTimeImmutable::W3C),
|
||||||
'completed_at' => $this->completedAt ? $this->completedAt->format(DateTimeImmutable::W3C) : null,
|
'updated_at' => $this->updatedAt->format(DateTimeImmutable::W3C),
|
||||||
'error' => Json::encode($this->error),
|
|
||||||
'data' => Json::encode($this->data),
|
'data' => Json::encode($this->data),
|
||||||
|
'error' => Json::encode($this->error),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,14 +162,16 @@ class AutomationRunLog {
|
|||||||
'code' => $error->getCode(),
|
'code' => $error->getCode(),
|
||||||
'trace' => $error->getTrace(),
|
'trace' => $error->getTrace(),
|
||||||
];
|
];
|
||||||
|
$this->updatedAt = new DateTimeImmutable();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function fromArray(array $data): self {
|
public static function fromArray(array $data): self {
|
||||||
$log = new AutomationRunLog((int)$data['automation_run_id'], $data['step_id']);
|
$log = new AutomationRunLog((int)$data['automation_run_id'], $data['step_id'], $data['step_type']);
|
||||||
$log->id = (int)$data['id'];
|
$log->id = (int)$data['id'];
|
||||||
|
$log->stepKey = $data['step_key'];
|
||||||
$log->status = $data['status'];
|
$log->status = $data['status'];
|
||||||
$log->startedAt = new DateTimeImmutable($data['started_at']);
|
$log->startedAt = new DateTimeImmutable($data['started_at']);
|
||||||
$log->completedAt = $data['completed_at'] ? new DateTimeImmutable($data['completed_at']) : null;
|
$log->updatedAt = new DateTimeImmutable($data['updated_at']);
|
||||||
$log->data = Json::decode($data['data']);
|
$log->data = Json::decode($data['data']);
|
||||||
$log->error = Json::decode($data['error']);
|
$log->error = Json::decode($data['error']);
|
||||||
return $log;
|
return $log;
|
||||||
|
@ -51,7 +51,7 @@ class AutomationRunLogTest extends \MailPoetTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function testItAllowsSettingSimpleData(): void {
|
public function testItAllowsSettingSimpleData(): void {
|
||||||
$log = new AutomationRunLog(1, 'step-id');
|
$log = new AutomationRunLog(1, 'step-id', AutomationRunLog::TYPE_ACTION);
|
||||||
$this->assertSame([], $log->getData());
|
$this->assertSame([], $log->getData());
|
||||||
$log->setData('key', 'value');
|
$log->setData('key', 'value');
|
||||||
$data = $log->getData();
|
$data = $log->getData();
|
||||||
@ -60,7 +60,7 @@ class AutomationRunLogTest extends \MailPoetTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function testItAllowsSettingArraysOfScalarValues(): void {
|
public function testItAllowsSettingArraysOfScalarValues(): void {
|
||||||
$log = new AutomationRunLog(1, 'step-id');
|
$log = new AutomationRunLog(1, 'step-id', AutomationRunLog::TYPE_ACTION);
|
||||||
$data = [
|
$data = [
|
||||||
'string',
|
'string',
|
||||||
11.1,
|
11.1,
|
||||||
@ -75,7 +75,7 @@ class AutomationRunLogTest extends \MailPoetTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function testItAllowsSettingMultidimensionalArraysOfScalarValues(): void {
|
public function testItAllowsSettingMultidimensionalArraysOfScalarValues(): void {
|
||||||
$log = new AutomationRunLog(1, 'step-id');
|
$log = new AutomationRunLog(1, 'step-id', AutomationRunLog::TYPE_ACTION);
|
||||||
$data = [
|
$data = [
|
||||||
'values' => [
|
'values' => [
|
||||||
'string',
|
'string',
|
||||||
@ -92,7 +92,7 @@ class AutomationRunLogTest extends \MailPoetTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function testItDoesNotAllowSettingDataThatIncludesClosures(): void {
|
public function testItDoesNotAllowSettingDataThatIncludesClosures(): void {
|
||||||
$log = new AutomationRunLog(1, 'step-id');
|
$log = new AutomationRunLog(1, 'step-id', AutomationRunLog::TYPE_ACTION);
|
||||||
$badData = [
|
$badData = [
|
||||||
function() {
|
function() {
|
||||||
echo 'closures cannot be serialized';
|
echo 'closures cannot be serialized';
|
||||||
@ -104,7 +104,7 @@ class AutomationRunLogTest extends \MailPoetTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function testItDoesNotAllowSettingObjectsForData(): void {
|
public function testItDoesNotAllowSettingObjectsForData(): void {
|
||||||
$log = new AutomationRunLog(1, 'step-id');
|
$log = new AutomationRunLog(1, 'step-id', AutomationRunLog::TYPE_ACTION);
|
||||||
$object = new stdClass();
|
$object = new stdClass();
|
||||||
$object->key = 'value';
|
$object->key = 'value';
|
||||||
$this->expectException(\InvalidArgumentException::class);
|
$this->expectException(\InvalidArgumentException::class);
|
||||||
@ -113,7 +113,7 @@ class AutomationRunLogTest extends \MailPoetTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function testItDoesNotAllowSettingMultidimensionalArrayThatContainsNonScalarValue(): void {
|
public function testItDoesNotAllowSettingMultidimensionalArrayThatContainsNonScalarValue(): void {
|
||||||
$log = new AutomationRunLog(1, 'step-id');
|
$log = new AutomationRunLog(1, 'step-id', AutomationRunLog::TYPE_ACTION);
|
||||||
$data = [
|
$data = [
|
||||||
'test' => [
|
'test' => [
|
||||||
'multidimensional' => [
|
'multidimensional' => [
|
||||||
@ -175,26 +175,26 @@ class AutomationRunLogTest extends \MailPoetTest {
|
|||||||
$automationRunLogs = $this->getLogsForAction();
|
$automationRunLogs = $this->getLogsForAction();
|
||||||
expect($automationRunLogs)->count(1);
|
expect($automationRunLogs)->count(1);
|
||||||
$log = $automationRunLogs[0];
|
$log = $automationRunLogs[0];
|
||||||
expect($log->getStatus())->equals('completed');
|
expect($log->getStatus())->equals('complete');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testItAddsCompletedAtTimestampAfterRunningSuccessfully(): void {
|
public function testItSetsUpdatedAtTimestampAfterRunningSuccessfully(): void {
|
||||||
$this->wp->addAction(Hooks::AUTOMATION_RUN_LOG_AFTER_STEP_RUN, function(AutomationRunLog $log) {
|
$this->wp->addAction(Hooks::AUTOMATION_RUN_LOG_AFTER_STEP_RUN, function(AutomationRunLog $log) {
|
||||||
expect($log->getCompletedAt())->null();
|
expect($log->getUpdatedAt())->null();
|
||||||
});
|
});
|
||||||
$automationRunLogs = $this->getLogsForAction();
|
$automationRunLogs = $this->getLogsForAction();
|
||||||
expect($automationRunLogs)->count(1);
|
expect($automationRunLogs)->count(1);
|
||||||
$log = $automationRunLogs[0];
|
$log = $automationRunLogs[0];
|
||||||
expect($log->getCompletedAt())->isInstanceOf(\DateTimeImmutable::class);
|
expect($log->getUpdatedAt())->isInstanceOf(\DateTimeImmutable::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testItAddsCompletedAtTimestampAfterFailing(): void {
|
public function testItSetsUpdatedAtTimestampAfterFailing(): void {
|
||||||
$automationRunLogs = $this->getLogsForAction(function() {
|
$automationRunLogs = $this->getLogsForAction(function() {
|
||||||
throw new \Exception('error');
|
throw new \Exception('error');
|
||||||
});
|
});
|
||||||
expect($automationRunLogs)->count(1);
|
expect($automationRunLogs)->count(1);
|
||||||
$log = $automationRunLogs[0];
|
$log = $automationRunLogs[0];
|
||||||
expect($log->getCompletedAt())->isInstanceOf(\DateTimeImmutable::class);
|
expect($log->getUpdatedAt())->isInstanceOf(\DateTimeImmutable::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testItLogsFailedStatusCorrectly(): void {
|
public function testItLogsFailedStatusCorrectly(): void {
|
||||||
|
@ -20,18 +20,18 @@ class AutomationRunLogStorageTest extends \MailPoetTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function testItSavesAndRetrievesAsExpected() {
|
public function testItSavesAndRetrievesAsExpected() {
|
||||||
$log = new AutomationRunLog(1, 'step-id');
|
$log = new AutomationRunLog(1, 'step-id', AutomationRunLog::TYPE_ACTION);
|
||||||
$log->setData('key', 'value');
|
$log->setData('key', 'value');
|
||||||
$log->setData('key2', ['arrayData']);
|
$log->setData('key2', ['arrayData']);
|
||||||
$preSave = $log->toArray();
|
$preSave = $log->toArray();
|
||||||
$id = $this->storage->createAutomationRunLog($log);
|
$id = $this->storage->createAutomationRunLog($log);
|
||||||
$fromDatabase = $this->storage->getAutomationRunLog($id);
|
$fromDatabase = $this->storage->getAutomationRunLog($id);
|
||||||
$this->assertInstanceOf(AutomationRunLog::class, $fromDatabase);
|
$this->assertInstanceOf(AutomationRunLog::class, $fromDatabase);
|
||||||
expect($preSave)->equals($fromDatabase->toArray());
|
expect(['id' => $fromDatabase->getId()] + $preSave)->equals($fromDatabase->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testItCanStoreAnError() {
|
public function testItCanStoreAnError() {
|
||||||
$log = new AutomationRunLog(1, 'step-id');
|
$log = new AutomationRunLog(1, 'step-id', AutomationRunLog::TYPE_ACTION);
|
||||||
$log->setError(new \Exception('test'));
|
$log->setError(new \Exception('test'));
|
||||||
$id = $this->storage->createAutomationRunLog($log);
|
$id = $this->storage->createAutomationRunLog($log);
|
||||||
$log = $this->storage->getAutomationRunLog($id);
|
$log = $this->storage->getAutomationRunLog($id);
|
||||||
|
@ -180,7 +180,7 @@ class AutomationStorageTest extends \MailPoetTest {
|
|||||||
$runId = $automationRunStorage->createAutomationRun($automationRun);
|
$runId = $automationRunStorage->createAutomationRun($automationRun);
|
||||||
$runs[$type][] = $runId;
|
$runs[$type][] = $runId;
|
||||||
for ($logI = 0; $logI < 2; $logI++) {
|
for ($logI = 0; $logI < 2; $logI++) {
|
||||||
$log = new AutomationRunLog($runId, "step-{$logI}");
|
$log = new AutomationRunLog($runId, "step-{$logI}", AutomationRunLog::TYPE_ACTION);
|
||||||
$logId = $automationRunLogStorage->createAutomationRunLog($log);
|
$logId = $automationRunLogStorage->createAutomationRunLog($log);
|
||||||
$runLogs[$type][] = $logId;
|
$runLogs[$type][] = $logId;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user