diff --git a/src/Logging/ErrorMessage.php b/src/Logging/ErrorMessage.php new file mode 100644 index 0000000..a7255d3 --- /dev/null +++ b/src/Logging/ErrorMessage.php @@ -0,0 +1,167 @@ + */ + private array $error_str = []; + /** @var \CoreLibs\Logging\Logging $log */ + public \CoreLibs\Logging\Logging $log; + + public function __construct( + \CoreLibs\Logging\Logging $log + ) { + $this->log = $log; + } + + /** + * pushes new error message into the error_str array + * error_id: internal Error ID (should be unique) + * level: error level, can only be ok, info, warn, error, abort, crash + * ok and info are positive response: success + * warn: success, but there might be some things that are not 100% ok + * error: input error or error in executing request + * abort: an internal error happened as mandatory information that normally is + * there is missing, or the ACL level that should normally match does not + * will be logged to "critical" + * crash: system failure or critical system problems (db connection failure) + * will be logged as "alert" + * not set: unkown, will be logged as "emergency" + * target/highlight: id target name for frontend where to attach this message + * highlight is a list of other target points to highlight + * + * @param string $error_id Any internal error ID for this error + * @param string $level Error level in ok/info/warn/error + * @param string $str Error message (out) + * @param string $target alternate attachment point for this error message + * @param array $highlight Any additional error data as error OR + * highlight points for field highlights + * @param string|null $message If abort/crash, non localized $str + * @param array $context Additionl info for abort/crash messages + */ + public function setErrorMsg( + string $error_id, + string $level, + string $str, + string $target = '', + array $highlight = [], + ?string $message = null, + array $context = [], + ): void { + $original_level = $level; + $level = MessageLevel::fromName($level)->name; + // if not string set, write message string if set, else level/error id + if (empty($str)) { + $str = $message ?? 'L:' . $level . '|E:' . $error_id; + } + $this->error_str[] = [ + 'id' => $error_id, + 'level' => $level, + 'str' => $str, + 'target' => $target, + 'highlight' => $highlight, + ]; + // write to log for abort/crash + switch ($level) { + case 'abort': + $this->log->critical($message ?? $str, array_merge([ + 'id' => $error_id, + 'level' => $original_level, + ], $context)); + break; + case 'crash': + $this->log->alert($message ?? $str, array_merge([ + 'id' => $error_id, + 'level' => $original_level, + ], $context)); + break; + case 'unknown': + $this->log->emergency($message ?? $str, array_merge([ + 'id' => $error_id, + 'level' => $original_level, + ], $context)); + break; + } + } + + /** + * pushes new error message into the error_str array + * Note, the parameter order is different and does not need an error id + * This is for backend alerts + * + * @param string $level error level (ok/warn/info/error) + * @param string $str error string + * @param string|null $error_id optional error id for precise error lookup + * @param string $target Alternate id name for output target on frontend + * @param array $highlight Any additional error data as error OR + * highlight points for field highlights + * @param string|null $message If abort/crash, non localized $str + * @param array $context Additionl info for abort/crash messages + */ + public function setErrorMsgLevel( + string $level, + string $str, + ?string $error_id = null, + string $target = '', + array $highlight = [], + ?string $message = null, + array $context = [], + ): void { + $this->setErrorMsg($error_id ?? '', $level, $str, $target, $highlight, $message, $context); + } + + // ********************************************************************* + // GETTERS + // ********************************************************************* + + /** + * Returns the current set error content from setErrorMsg method + * + * @return array Error messages array + */ + public function getErrorMsg(): array + { + return $this->error_str; + } + + /** + * Current set error ids + * + * @return array + */ + public function getErrorIds(): array + { + return array_column($this->error_str, 'id'); + } + + /** + * Gets the LAST entry in the array list. + * If nothing found returns empty array set + * + * @return array{id:string,level:string,str:string,target:string,highlight:string[]} Error block + */ + public function getLastErrorMsg(): array + { + return $this->error_str[array_key_last($this->error_str)] ?? [ + 'level' => '', + 'str' => '', + 'id' => '', + 'target' => '', + 'highlight' => [], + ]; + } +} + +// __END__ diff --git a/src/Logging/Logger/Level.php b/src/Logging/Logger/Level.php index 355dce4..ba497f7 100644 --- a/src/Logging/Logger/Level.php +++ b/src/Logging/Logger/Level.php @@ -113,17 +113,32 @@ enum Level: int /** * Returns true if the passed $level is higher or equal to $this + * + * @param Level $level + * @return bool */ public function includes(Level $level): bool { return $this->value <= $level->value; } + /** + * If level is higher than set one + * + * @param Level $level + * @return bool + */ public function isHigherThan(Level $level): bool { return $this->value > $level->value; } + /** + * if level is lower than set one + * + * @param Level $level + * @return bool + */ public function isLowerThan(Level $level): bool { return $this->value < $level->value; diff --git a/src/Logging/Logger/MessageLevel.php b/src/Logging/Logger/MessageLevel.php new file mode 100644 index 0000000..40f1170 --- /dev/null +++ b/src/Logging/Logger/MessageLevel.php @@ -0,0 +1,51 @@ + self::ok, + 'info' => self::info, + 'warn', 'warning' => self::warn, + 'error' => self::error, + 'abort' => self::abort, + 'crash' => self::crash, + default => self::unknown, + }; + } + + /** + * @param int $value + * @return static + */ + public static function fromValue(int $value): self + { + return self::tryFrom($value) ?? self::unknown; + } +} + +// __END__ diff --git a/test/phpunit/Logging/CoreLibsLoggingErrorMessagesTest.php b/test/phpunit/Logging/CoreLibsLoggingErrorMessagesTest.php new file mode 100644 index 0000000..72012e4 --- /dev/null +++ b/test/phpunit/Logging/CoreLibsLoggingErrorMessagesTest.php @@ -0,0 +1,284 @@ + [ + 'level' => 'ok', + 'str' => 'OK', + 'expected' => 'ok', + ], + 'info' => [ + 'level' => 'info', + 'str' => 'INFO', + 'expected' => 'info', + ], + 'warn' => [ + 'level' => 'warn', + 'str' => 'WARN', + 'expected' => 'warn' + ], + 'warning' => [ + 'level' => 'warning', + 'str' => 'WARN', + 'expected' => 'warn' + ], + 'error' => [ + 'level' => 'error', + 'str' => 'ERROR', + 'expected' => 'error' + ], + 'abort' => [ + 'level' => 'abort', + 'str' => 'ABORT', + 'expected' => 'abort' + ], + 'crash' => [ + 'level' => 'crash', + 'str' => 'CRASH', + 'expected' => 'crash' + ], + 'wrong level' => [ + 'level' => 'wrong', + 'str' => 'WRONG', + 'expected' => 'unknown' + ] + ]; + } + + /** + * Undocumented function + * + * @dataProvider providerErrorMessageLevel + * @testdox error message level: $level will be $expected [$_dataName] + * + * @param string $level + * @param string $str + * @param string $expected + * @return void + */ + public function testErrorMessageLevelOk(string $level, string $str, string $expected): void + { + $log = new \CoreLibs\Logging\Logging([ + 'log_file_id' => 'testErrorMessages', + 'log_folder' => self::LOG_FOLDER, + 'log_level' => Level::Debug, + ]); + $em = new \CoreLibs\Logging\ErrorMessage($log); + $em->setErrorMsgLevel( + $level, + $str + ); + $this->assertEquals( + [ + 'level' => $expected, + 'str' => $str, + 'id' => '', + 'target' => '', + 'highlight' => [], + ], + $em->getLastErrorMsg() + ); + } + + /** + * Undocumented function + * + * @testdox Test of all methods for n messages [$_dataName] + * + * @return void + */ + public function testErrorMessageOk(): void + { + $log = new \CoreLibs\Logging\Logging([ + 'log_file_id' => 'testErrorMessages', + 'log_folder' => self::LOG_FOLDER, + 'log_level' => Level::Debug + ]); + $em = new \CoreLibs\Logging\ErrorMessage($log); + $em->setErrorMsg( + '100', + 'info', + 'INFO MESSAGE' + ); + + $this->assertEquals( + [ + 'id' => '100', + 'level' => 'info', + 'str' => 'INFO MESSAGE', + 'target' => '', + 'highlight' => [], + ], + $em->getLastErrorMsg() + ); + $this->assertEquals( + ['100'], + $em->getErrorIds() + ); + $this->assertEquals( + [ + [ + 'id' => '100', + 'level' => 'info', + 'str' => 'INFO MESSAGE', + 'target' => '', + 'highlight' => [], + ] + ], + $em->getErrorMsg() + ); + + $em->setErrorMsg( + '200', + 'error', + 'ERROR MESSAGE' + ); + $this->assertEquals( + [ + 'id' => '200', + 'level' => 'error', + 'str' => 'ERROR MESSAGE', + 'target' => '', + 'highlight' => [], + ], + $em->getLastErrorMsg() + ); + $this->assertEquals( + ['100', '200'], + $em->getErrorIds() + ); + $this->assertEquals( + [ + [ + 'id' => '100', + 'level' => 'info', + 'str' => 'INFO MESSAGE', + 'target' => '', + 'highlight' => [], + ], + [ + 'id' => '200', + 'level' => 'error', + 'str' => 'ERROR MESSAGE', + 'target' => '', + 'highlight' => [], + ] + ], + $em->getErrorMsg() + ); + } + + public function providerErrorMessageLog(): array + { + return [ + 'crash' => [ + 'id' => '300', + 'level' => 'crash', + 'str' => 'CRASH MESSAGE', + 'message' => null, + 'expected' => ' CRASH MESSAGE', + ], + 'crash, message' => [ + 'id' => '300', + 'level' => 'crash', + 'str' => 'CRASH MESSAGE', + 'message' => 'OTHER CRASH MESSAGE', + 'expected' => ' OTHER CRASH MESSAGE', + ], + 'abort' => [ + 'id' => '200', + 'level' => 'abort', + 'str' => 'ABORT MESSAGE', + 'message' => null, + 'expected' => ' ABORT MESSAGE', + ], + 'abort, message' => [ + 'id' => '200', + 'level' => 'abort', + 'str' => 'ABORT MESSAGE', + 'message' => 'OTHER ABORT MESSAGE', + 'expected' => ' OTHER ABORT MESSAGE', + ], + 'unknown' => [ + 'id' => '400', + 'level' => 'wrong level', + 'str' => 'WRONG LEVEL MESSAGE', + 'message' => null, + 'expected' => ' WRONG LEVEL MESSAGE', + ], + 'unknown, message' => [ + 'id' => '400', + 'level' => 'wrong level', + 'str' => 'WRONG LEVEL MESSAGE', + 'message' => 'OTHER WRONG LEVEL MESSAGE', + 'expected' => ' OTHER WRONG LEVEL MESSAGE', + ], + ]; + } + + /** + * Undocumented function + * + * @dataProvider providerErrorMessageLog + * @testdox Test Log writing [$_dataName] + * + * @return void + */ + public function testErrorMessageLog(string $id, string $level, string $str, ?string $message, string $expected) + { + $log = new \CoreLibs\Logging\Logging([ + 'log_file_id' => 'testErrorMessages', + 'log_folder' => self::LOG_FOLDER, + 'log_level' => Level::Debug, + 'log_per_run' => true + ]); + $em = new \CoreLibs\Logging\ErrorMessage($log); + $em->setErrorMsg( + $id, + $level, + $str, + message: $message + ); + $file_content = file_get_contents( + $log->getLogFolder() . $log->getLogFile() + ) ?: ''; + $this->assertStringContainsString( + $expected, + $file_content + ); + } +} + +// __END__