diff --git a/src/ZM/Command/Command.php b/src/ZM/Command/Command.php index c685a5fd..77f77191 100644 --- a/src/ZM/Command/Command.php +++ b/src/ZM/Command/Command.php @@ -4,11 +4,11 @@ declare(strict_types=1); namespace ZM\Command; +use Psr\Log\LoggerInterface; use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\Console\Output\OutputInterface; -abstract class Command extends \Symfony\Component\Console\Command\Command +abstract class Command extends \Symfony\Component\Console\Command\Command implements LoggerInterface { use CommandInteractTrait; diff --git a/src/ZM/Command/CommandInteractTrait.php b/src/ZM/Command/CommandInteractTrait.php index 7344a7ba..02ee99a5 100644 --- a/src/ZM/Command/CommandInteractTrait.php +++ b/src/ZM/Command/CommandInteractTrait.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace ZM\Command; +use Psr\Log\LogLevel; use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Helper\QuestionHelper; use Symfony\Component\Console\Input\InputInterface; @@ -18,6 +19,119 @@ use ZM\Exception\ZMException; */ trait CommandInteractTrait { + /** + * System is unusable. + * + * @param string $message + * @param mixed[] $context + */ + public function emergency($message, array $context = []) + { + $this->log(LogLevel::EMERGENCY, $message, $context); + } + + /** + * Action must be taken immediately. + * + * Example: Entire website down, database unavailable, etc. This should + * trigger the SMS alerts and wake you up. + * + * @param string $message + * @param mixed[] $context + */ + public function alert($message, array $context = []) + { + $this->log(LogLevel::ALERT, $message, $context); + } + + /** + * Critical conditions. + * + * Example: Application component unavailable, unexpected exception. + * + * @param string $message + * @param mixed[] $context + */ + public function critical($message, array $context = []) + { + $this->log(LogLevel::CRITICAL, $message, $context); + } + + /** + * Runtime errors that do not require immediate action but should typically + * be logged and monitored. + * + * @param string $message + * @param mixed[] $context + */ + public function error($message, array $context = []) + { + $this->log(LogLevel::ERROR, $message, $context); + } + + /** + * Exceptional occurrences that are not errors. + * + * Example: Use of deprecated APIs, poor use of an API, undesirable things + * that are not necessarily wrong. + * + * @param string $message + * @param mixed[] $context + */ + public function warning($message, array $context = []) + { + $this->log(LogLevel::WARNING, $message, $context); + } + + /** + * Normal but significant events. + * + * @param string $message + * @param mixed[] $context + */ + public function notice($message, array $context = []) + { + $this->log(LogLevel::NOTICE, $message, $context); + } + + /** + * Interesting events. + * + * Example: User logs in, SQL logs. + * + * @param string $message + */ + public function info($message, array $context = []) + { + $this->log(LogLevel::INFO, $message, $context); + } + + /** + * Detailed debug information. + * + * @param string $message + */ + public function debug($message, array $context = []) + { + $this->log(LogLevel::DEBUG, $message, $context); + } + + public function log($level, $message, array $context = []) + { + $msg = match ($level) { + 'info' => "{$message}", + 'debug' => $this->input->getOption('verbose') ? "{$message}" : '', + 'notice' => "{$message}", + 'warning' => "{$message}", + 'error', 'critical', 'alert', 'emergency' => "{$message}", + default => '', + }; + $msg = $this->interpolate($msg, $context); + if ($msg !== '') { + $this->output->write($msg, true); + } + } + /** * 输出一段文本,默认样式 * @@ -30,28 +144,6 @@ trait CommandInteractTrait $this->output->write($message, $newline); } - /** - * 输出文本,一般用于提示信息 - * - * @param string $message 要输出的文本 - * @param bool $newline 是否在文本后换行 - */ - public function info(string $message, bool $newline = true): void - { - $this->write("{$message}", $newline); - } - - /** - * 输出文本,一般用于错误信息 - * - * @param string $message 要输出的文本 - * @param bool $newline 是否在文本后换行 - */ - public function error(string $message, bool $newline = true): void - { - $this->write("{$message}", $newline); - } - /** * 输出文本,一般用于警告或附注信息 * @@ -157,4 +249,45 @@ trait CommandInteractTrait exit(self::SUCCESS); } } + + private function interpolate(string $message, array $context = []): string + { + $replace = []; + foreach ($context as $key => $value) { + $replace['{' . $key . '}'] = $this->stringify($value); + } + + return strtr($message, $replace); + } + + private function stringify($item): string + { + switch (true) { + case is_callable($item): + if (is_array($item)) { + if (is_object($item[0])) { + return get_class($item[0]) . '@' . $item[1]; + } + return $item[0] . '::' . $item[1]; + } + return 'closure'; + case is_string($item): + return $item; + case is_array($item): + return 'array' . (extension_loaded('json') ? json_encode($item, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_LINE_TERMINATORS) : ''); + case is_object($item): + return get_class($item); + case is_resource($item): + return 'resource(' . get_resource_type($item) . ')'; + case is_null($item): + return 'null'; + case is_bool($item): + return $item ? 'true' : 'false'; + case is_float($item): + case is_int($item): + return (string) $item; + default: + return 'unknown'; + } + } } diff --git a/src/ZM/Framework.php b/src/ZM/Framework.php index c4134b74..f61b63bf 100644 --- a/src/ZM/Framework.php +++ b/src/ZM/Framework.php @@ -47,7 +47,7 @@ class Framework public const VERSION_ID = 697; /** @var string 版本名称 */ - public const VERSION = '3.0.3'; + public const VERSION = '3.1.0'; /** @var array 传入的参数 */ protected array $argv;