From 81d4558b2f079a16d1124f034b0ba3706b602432 Mon Sep 17 00:00:00 2001 From: sunxyw Date: Sun, 22 May 2022 20:56:05 +0800 Subject: [PATCH 1/5] add master support for logger --- config/logging.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/config/logging.php b/config/logging.php index 5518c548..80f0e458 100644 --- a/config/logging.php +++ b/config/logging.php @@ -9,10 +9,11 @@ use ZM\Logger\ConsoleLogger; return [ 'level' => LogLevel::DEBUG, 'logger' => static function (): LoggerInterface { - $worker_id = app('worker_id'); + // 在 Master 中,worker_id 将不存在 + $worker_id = app()->has('worker_id') ? '#' . app('worker_id') : 'Master'; $logger = new ConsoleLogger(zm_config('logging.level')); - $logger::$format = "[%date%] [%level%] [#{$worker_id}] %body%"; + $logger::$format = "[%date%] [%level%] [{$worker_id}] %body%"; $logger::$date_format = 'Y-m-d H:i:s'; // 如果你喜欢旧版的日志格式,请取消下行注释 // $logger::$date_format = 'm-d H:i:s'; From 09780f64de717dea71f3b6ce597cac71ae9cebe6 Mon Sep 17 00:00:00 2001 From: sunxyw Date: Sun, 22 May 2022 20:58:23 +0800 Subject: [PATCH 2/5] refactor framework class logging --- src/ZM/Framework.php | 388 ++++++++++++++++++++++++------------------- 1 file changed, 213 insertions(+), 175 deletions(-) diff --git a/src/ZM/Framework.php b/src/ZM/Framework.php index 34bde60e..626d6217 100644 --- a/src/ZM/Framework.php +++ b/src/ZM/Framework.php @@ -7,7 +7,9 @@ namespace ZM; use Doctrine\Common\Annotations\AnnotationReader; use Error; use Exception; +use InvalidArgumentException; use Phar; +use Psr\Log\LoggerInterface; use ReflectionClass; use ReflectionException; use Swoole\Runtime; @@ -18,6 +20,7 @@ use ZM\Annotation\Swoole\SwooleHandler; use ZM\Config\ZMConfig; use ZM\ConnectionManager\ManagerGM; use ZM\Console\Console; +use ZM\Container\WorkerContainer; use ZM\Exception\ConfigException; use ZM\Logger\TablePrinter; use ZM\Store\LightCache; @@ -135,6 +138,9 @@ class Framework Console::setOutputFile(ZMConfig::get('global', 'runtime')['save_console_log_file']); } + // TODO: remove tmp statement + WorkerContainer::getInstance()->singleton(LoggerInterface::class, ZMConfig::get('logging.logger')); + // 设置默认时区 $timezone = ZMConfig::get('global', 'timezone') ?? 'Asia/Shanghai'; date_default_timezone_set($timezone); @@ -144,7 +150,7 @@ class Framework $this->swoole_server_config['log_level'] = SWOOLE_LOG_DEBUG; // 是否启用远程终端 - $add_port = ZMConfig::get('global', 'remote_terminal')['status'] ?? false; + $remote_terminal = ZMConfig::get('global', 'remote_terminal')['status'] ?? false; // 加载服务器事件 if (!$instant_mode) { @@ -152,7 +158,7 @@ class Framework } // 解析命令行参数 - $coroutine_mode = $this->parseCliArgs(self::$argv, $add_port); + [$coroutine_mode, $terminal_id, $remote_terminal] = $this->parseCliArgs(self::$argv, compact('remote_terminal')); // 设置默认最长等待时间 if (!isset($this->swoole_server_config['max_wait_time'])) { @@ -167,57 +173,7 @@ class Framework // 非静默模式下打印启动信息 if (!self::$argv['private-mode']) { - $out['working_dir'] = DataProvider::getWorkingDir(); - $out['listen'] = ZMConfig::get('global', 'host') . ':' . ZMConfig::get('global', 'port'); - if (!isset($this->swoole_server_config['worker_num'])) { - if ((ZMConfig::get('global', 'runtime')['swoole_server_mode'] ?? SWOOLE_PROCESS) === SWOOLE_PROCESS) { - $out['worker'] = swoole_cpu_num() . ' (auto)'; - } else { - $out['single_proc_mode'] = 'true'; - } - } else { - $out['worker'] = $this->swoole_server_config['worker_num']; - } - $out['environment'] = ($args['env'] ?? null) === null ? 'default' : $args['env']; - $out['log_level'] = Console::getLevel(); - $out['version'] = Framework::VERSION . (LOAD_MODE === 0 ? (' (build ' . ZM_VERSION_ID . ')') : ''); - $out['master_pid'] = posix_getpid(); - if (APP_VERSION !== 'unknown') { - $out['app_version'] = APP_VERSION; - } - if (isset($this->swoole_server_config['task_worker_num'])) { - $out['task_worker'] = $this->swoole_server_config['task_worker_num']; - } - if ((ZMConfig::get('global', 'sql_config')['sql_host'] ?? '') !== '') { - $conf = ZMConfig::get('global', 'sql_config'); - $out['mysql_pool'] = $conf['sql_database'] . '@' . $conf['sql_host'] . ':' . $conf['sql_port']; - } - if ((ZMConfig::get('global', 'mysql_config')['host'] ?? '') !== '') { - $conf = ZMConfig::get('global', 'mysql_config'); - $out['mysql'] = $conf['dbname'] . '@' . $conf['host'] . ':' . $conf['port']; - } - if (ZMConfig::get('global', 'redis_config')['host'] !== '') { - $conf = ZMConfig::get('global', 'redis_config'); - $out['redis_pool'] = $conf['host'] . ':' . $conf['port']; - } - if (ZMConfig::get('global', 'static_file_server')['status'] !== false) { - $out['static_file_server'] = 'enabled'; - } - if (self::$argv['show-php-ver'] !== false) { - $out['php_version'] = PHP_VERSION; - $out['swoole_version'] = SWOOLE_VERSION; - } - - if ($add_port) { - $conf = ZMConfig::get('global', 'remote_terminal'); - $out['terminal'] = $conf['host'] . ':' . $conf['port']; - } - if (LOAD_MODE === 0) { - echo Console::setColor("* Framework started with source mode.\n", $args['log-theme'] === null ? 'yellow' : ''); - } - // $this->mapOutput($out); // 汉化操作 - $printer = new TablePrinter($out); - $printer->setValueColor('random')->printAll(); + $this->printProperties($remote_terminal, $args); } // 预览模式则直接提出 @@ -233,7 +189,7 @@ class Framework ); // 监听远程终端 - if ($add_port) { + if ($remote_terminal) { $conf = ZMConfig::get('global', 'remote_terminal') ?? [ 'status' => true, 'host' => '127.0.0.1', @@ -317,7 +273,7 @@ class Framework // 非静默模式下,打印欢迎信息 if (!self::$argv['private-mode']) { - self::printMotd(isset($printer) ? $printer->fetchTerminalSize() : 79); + $this->printMotd(); } $global_hook = ZMConfig::get('global', 'runtime')['swoole_coroutine_hook_flags'] ?? (SWOOLE_HOOK_ALL & (~SWOOLE_HOOK_CURL)); @@ -384,33 +340,18 @@ class Framework return true; }, E_ALL | E_STRICT); } catch (Exception $e) { - Console::error('框架初始化出现异常,请检查!'); - Console::error(zm_internal_errcode('E00010') . $e->getMessage()); + logger()->emergency('框架初始化失败,请检查!'); + logger()->emergency(zm_internal_errcode('E00010') . $e->getMessage()); if (strpos($e->getMessage(), 'Address already in use') !== false) { if (!ProcessManager::isStateEmpty()) { - Console::error('检测到可能残留框架的工作进程,请先通过命令杀死:server:stop --force'); + logger()->alert('检测到可能残留框架的工作进程,请先通过命令杀死:server:stop --force'); } } - Console::debug($e); + logger()->debug($e); exit; } } - public function start() - { - try { - self::$loaded_files = get_included_files(); - LightCacheInside::set('tmp_kv', 'start_time', microtime(true)); - self::$server->start(); - zm_atomic('server_is_stopped')->set(1); - if (!self::$argv['private-mode']) { - Console::log('zhamao-framework is stopped.'); - } - } catch (Throwable $e) { - exit(zm_internal_errcode('E00011') . 'Framework has an uncaught ' . get_class($e) . ': ' . $e->getMessage() . PHP_EOL); - } - } - public static function loadFrameworkState() { if (!file_exists(DataProvider::getDataFolder() . '.state.json')) { @@ -428,26 +369,27 @@ class Framework return file_put_contents(DataProvider::getDataFolder() . '.state.json', json_encode($data, 64 | 128 | 256)); } - public function mapOutput(array &$out) + public function start() { - $translate = [ - 'working_dir' => '工作目录', - 'listen' => '监听地址', - 'worker' => '工作进程数', - 'environment' => '环境类型', - 'log_level' => '日志级别', - 'version' => '框架版本', - 'master_pid' => '主进程PID', - ]; - foreach ($out as $k => $v) { - if (isset($translate[$k])) { - $this->arrayChangeKey($out, $k, $translate[$k]); + try { + self::$loaded_files = get_included_files(); + LightCacheInside::set('tmp_kv', 'start_time', microtime(true)); + self::$server->start(); + zm_atomic('server_is_stopped')->set(1); + if (!self::$argv['private-mode']) { + Console::log('zhamao-framework is stopped.'); } + } catch (Throwable $e) { + exit(zm_internal_errcode('E00011') . 'Framework has an uncaught ' . get_class($e) . ': ' . $e->getMessage() . PHP_EOL); } } - private static function printMotd($tty_width) + /** + * 打印 MOTD + */ + private function printMotd(): void { + $tty_width = (new TablePrinter([]))->fetchTerminalSize(); if (file_exists(DataProvider::getSourceRootDir() . '/config/motd.txt')) { $motd = file_get_contents(DataProvider::getSourceRootDir() . '/config/motd.txt'); } else { @@ -462,8 +404,34 @@ class Framework } /** - * @noinspection PhpIncludeInspection + * 翻译属性 */ + private function translateProperties(array &$properties): void + { + $translations = [ + 'working_dir' => '工作目录', + 'listen' => '监听地址', + 'worker' => '工作进程数', + 'environment' => '环境类型', + 'log_level' => '日志级别', + 'version' => '框架版本', + 'master_pid' => '主进程 PID', + 'app_version' => '应用版本', + 'task_worker' => '任务进程数', + 'mysql_pool' => '数据库', + 'mysql' => '数据库', + 'redis_pool' => 'Redis', + 'static_file_server' => '静态文件托管', + 'php_version' => 'PHP 版本', + 'swoole_version' => 'Swoole 版本', + ]; + foreach ($properties as $k => $v) { + if (isset($translations[$k])) { + $this->changeArrayKey($properties, $k, $translations[$k]); + } + } + } + private function loadServerEvents() { if (Phar::running() !== '') { @@ -523,104 +491,174 @@ class Framework } /** - * 解析命令行的 $argv 参数们 + * 解析命令行的 $argv 参数 * - * @param array $args 命令行参数 - * @param bool|string $add_port 是否添加端口号 - * @throws ConfigException + * @param array $args 命令行参数 + * @throws InvalidArgumentException 参数不正确,框架需要捕获并终止启动 + * @return array 解析后并需要处理的参数 */ - private function parseCliArgs(array $args, &$add_port) + private function parseCliArgs(array $args, array $defaults): array { $coroutine_mode = true; global $terminal_id; $terminal_id = uuidgen(); + $error_occur = false; + $remote_terminal = $defaults['remote_terminal']; + foreach ($args as $x => $y) { - if ($y) { - switch ($x) { - case 'worker-num': - if (intval($y) >= 1 && intval($y) <= 1024) { - $this->swoole_server_config['worker_num'] = intval($y); - } else { - Console::warning(zm_internal_errcode('E00013') . 'Invalid worker num! Turn to default value (' . ($this->swoole_server_config['worker_num'] ?? swoole_cpu_num()) . ')'); - } - break; - case 'task-worker-num': - if (intval($y) >= 1 && intval($y) <= 1024) { - $this->swoole_server_config['task_worker_num'] = intval($y); - $this->swoole_server_config['task_enable_coroutine'] = true; - } else { - Console::warning(zm_internal_errcode('E00013') . 'Invalid worker num! Turn to default value (0)'); - } - break; - case 'disable-coroutine': - $coroutine_mode = false; - break; - case 'debug-mode': - self::$argv['disable-safe-exit'] = true; - $coroutine_mode = false; - $terminal_id = null; - self::$argv['watch'] = true; - echo "* You are in debug mode, do not use in production!\n"; - break; - case 'daemon': - $this->swoole_server_config['daemonize'] = 1; - Console::$theme = 'no-color'; - Console::log('已启用守护进程,输出重定向到 ' . $this->swoole_server_config['log_file']); - $terminal_id = null; - break; - case 'disable-console-input': - case 'no-interaction': - $terminal_id = null; - break; - case 'log-error': - Console::setLevel(0); - break; - case 'log-warning': - Console::setLevel(1); - break; - case 'log-info': - Console::setLevel(2); - break; - case 'log-verbose': - case 'verbose': - Console::setLevel(3); - break; - case 'log-debug': - Console::setLevel(4); - break; - case 'audit-mode': - Console::warning('审计模式已开启,请正常执行需要审计的流程,然后Ctrl+C正常结束框架'); - Console::warning('审计的日志文件将存放到:' . DataProvider::getWorkingDir() . '/audit.log'); - if (file_exists(DataProvider::getWorkingDir() . '/audit.log')) { - unlink(DataProvider::getWorkingDir() . '/audit.log'); - } - Console::info('框架将于5秒后开始启动...'); - Console::setOutputFile(DataProvider::getWorkingDir() . '/audit.log'); - Console::setLevel(4); - sleep(5); - break; - case 'log-theme': - Console::$theme = $y; - break; - case 'remote-terminal': - $add_port = true; - break; - case 'show-php-ver': - default: - // Console::info("Calculating ".$x); - // dump($y); - break; - } + if ($y === false || is_null($y)) { + continue; + } + switch ($x) { + case 'worker-num': + if ((int) $y >= 1 && (int) $y <= 1024) { + $this->swoole_server_config['worker_num'] = (int) $y; + } else { + logger()->emergency(zm_internal_errcode('E00013') . '传入的 worker_num 参数不合法!必须在 1-1024 之间!'); + $error_occur = true; + } + break; + case 'task-worker-num': + if ((int) $y >= 1 && (int) $y <= 1024) { + $this->swoole_server_config['task_worker_num'] = (int) $y; + $this->swoole_server_config['task_enable_coroutine'] = true; + } else { + logger()->emergency(zm_internal_errcode('E00013') . '传入的 task_worker_num 参数不合法!必须在 1-1024 之间!'); + $error_occur = true; + } + break; + case 'disable-coroutine': + $coroutine_mode = false; + break; + case 'debug-mode': + self::$argv['disable-safe-exit'] = true; + $coroutine_mode = false; + $terminal_id = null; + self::$argv['watch'] = true; + logger()->notice('已进入调试模式,请勿在生产环境中使用!'); + break; + case 'daemon': + $this->swoole_server_config['daemonize'] = 1; + Console::$theme = 'no-color'; + Console::log('已启用守护进程,输出重定向到 ' . $this->swoole_server_config['log_file']); + $terminal_id = null; + break; + case 'disable-console-input': + case 'no-interaction': + $terminal_id = null; + break; + case 'log-error': + Console::setLevel(0); + break; + case 'log-warning': + Console::setLevel(1); + break; + case 'log-info': + Console::setLevel(2); + break; + case 'log-verbose': + case 'verbose': + Console::setLevel(3); + break; + case 'log-debug': + Console::setLevel(4); + break; + case 'audit-mode': + logger()->notice('审计模式已开启,请正常执行需要审计的流程,然后Ctrl+C正常结束框架'); + logger()->notice('审计的日志文件将存放到:' . DataProvider::getWorkingDir() . '/audit.log'); + if (file_exists(DataProvider::getWorkingDir() . '/audit.log')) { + unlink(DataProvider::getWorkingDir() . '/audit.log'); + } + logger()->notice('框架将于5秒后开始启动...'); + Console::setOutputFile(DataProvider::getWorkingDir() . '/audit.log'); + Console::setLevel(4); + sleep(5); + break; + case 'log-theme': + Console::$theme = $y; + break; + case 'remote-terminal': + $remote_terminal = true; + break; + case 'show-php-ver': + default: + break; } } - return $coroutine_mode; + if ($error_occur) { + throw new InvalidArgumentException('命令行参数解析错误,请参阅上方日志!'); + } + return [$coroutine_mode, $terminal_id, $remote_terminal]; } - private function arrayChangeKey(array &$arr, $old_key, $new_key) + /** + * 更换数组键名 + * @param mixed $old_key + * @param mixed $new_key + */ + private function changeArrayKey(array &$arr, $old_key, $new_key): void { $keys = array_keys($arr); - $values = array_values($arr); - $keys[array_search($old_key, $keys)] = $new_key; - $arr = array_combine($keys, $values); + $keys[array_search($old_key, $keys, false)] = $new_key; + $arr = ($t = array_combine($keys, $arr)) ? $t : $arr; + } + + /** + * 打印属性表格 + */ + private function printProperties(bool $remote_terminal, array $args): void + { + $properties = []; + $properties['working_dir'] = DataProvider::getWorkingDir(); + $properties['listen'] = ZMConfig::get('global', 'host') . ':' . ZMConfig::get('global', 'port'); + if (!isset($this->swoole_server_config['worker_num'])) { + if ((ZMConfig::get('global', 'runtime')['swoole_server_mode'] ?? SWOOLE_PROCESS) === SWOOLE_PROCESS) { + $properties['worker'] = swoole_cpu_num() . ' (auto)'; + } else { + $properties['single_proc_mode'] = 'true'; + } + } else { + $properties['worker'] = $this->swoole_server_config['worker_num']; + } + $properties['environment'] = ($args['env'] ?? null) === null ? 'default' : $args['env']; + $properties['log_level'] = strtoupper(zm_config('logging.level')); + $properties['version'] = self::VERSION . (LOAD_MODE === 0 ? (' (build ' . ZM_VERSION_ID . ')') : ''); + $properties['master_pid'] = posix_getpid(); + if (APP_VERSION !== 'unknown') { + $properties['app_version'] = APP_VERSION; + } + if (isset($this->swoole_server_config['task_worker_num'])) { + $properties['task_worker'] = $this->swoole_server_config['task_worker_num']; + } + if ((ZMConfig::get('global', 'sql_config')['sql_host'] ?? '') !== '') { + $conf = ZMConfig::get('global', 'sql_config'); + $properties['mysql_pool'] = $conf['sql_database'] . '@' . $conf['sql_host'] . ':' . $conf['sql_port']; + } + if ((ZMConfig::get('global', 'mysql_config')['host'] ?? '') !== '') { + $conf = ZMConfig::get('global', 'mysql_config'); + $properties['mysql'] = $conf['dbname'] . '@' . $conf['host'] . ':' . $conf['port']; + } + if (ZMConfig::get('global', 'redis_config')['host'] !== '') { + $conf = ZMConfig::get('global', 'redis_config'); + $properties['redis_pool'] = $conf['host'] . ':' . $conf['port']; + } + if (ZMConfig::get('global', 'static_file_server')['status'] !== false) { + $properties['static_file_server'] = 'enabled'; + } + if (self::$argv['show-php-ver'] !== false) { + $properties['php_version'] = PHP_VERSION; + $properties['swoole_version'] = SWOOLE_VERSION; + } + + if ($remote_terminal) { + $conf = ZMConfig::get('global', 'remote_terminal'); + $properties['terminal'] = $conf['host'] . ':' . $conf['port']; + } + if (LOAD_MODE === 0) { + logger()->info('框架正以源码模式启动'); + } + $this->translateProperties($properties); + $printer = new TablePrinter($properties); + $printer->setValueColor('random')->printAll(); } } From c106c4fc2a3b0bffe788ad936171a1148724a76d Mon Sep 17 00:00:00 2001 From: sunxyw Date: Sun, 22 May 2022 22:18:04 +0800 Subject: [PATCH 3/5] cleanup framework class logging --- src/ZM/Framework.php | 62 ++++++++++++------------------------- src/ZM/global_functions.php | 3 ++ 2 files changed, 23 insertions(+), 42 deletions(-) diff --git a/src/ZM/Framework.php b/src/ZM/Framework.php index 626d6217..378cfe90 100644 --- a/src/ZM/Framework.php +++ b/src/ZM/Framework.php @@ -9,7 +9,6 @@ use Error; use Exception; use InvalidArgumentException; use Phar; -use Psr\Log\LoggerInterface; use ReflectionClass; use ReflectionException; use Swoole\Runtime; @@ -20,7 +19,6 @@ use ZM\Annotation\Swoole\SwooleHandler; use ZM\Config\ZMConfig; use ZM\ConnectionManager\ManagerGM; use ZM\Console\Console; -use ZM\Container\WorkerContainer; use ZM\Exception\ConfigException; use ZM\Logger\TablePrinter; use ZM\Store\LightCache; @@ -121,7 +119,7 @@ class Framework ], ]); } catch (ConnectionManager\TableException $e) { - echo zm_internal_errcode('E00008') . $e->getMessage() . PHP_EOL; + logger()->emergency(zm_internal_errcode('E00008') . $e->getMessage()); exit(1); } @@ -138,9 +136,6 @@ class Framework Console::setOutputFile(ZMConfig::get('global', 'runtime')['save_console_log_file']); } - // TODO: remove tmp statement - WorkerContainer::getInstance()->singleton(LoggerInterface::class, ZMConfig::get('logging.logger')); - // 设置默认时区 $timezone = ZMConfig::get('global', 'timezone') ?? 'Asia/Shanghai'; date_default_timezone_set($timezone); @@ -305,37 +300,20 @@ class Framework // 注册全局错误处理器 set_error_handler(static function ($error_no, $error_msg, $error_file, $error_line) { - switch ($error_no) { - case E_WARNING: - $level_tips = 'PHP Warning: '; - break; - case E_NOTICE: - $level_tips = 'PHP Notice: '; - break; - case E_DEPRECATED: - $level_tips = 'PHP Deprecated: '; - break; - case E_USER_ERROR: - $level_tips = 'User Error: '; - break; - case E_USER_WARNING: - $level_tips = 'User Warning: '; - break; - case E_USER_NOTICE: - $level_tips = 'User Notice: '; - break; - case E_USER_DEPRECATED: - $level_tips = 'User Deprecated: '; - break; - case E_STRICT: - $level_tips = 'PHP Strict: '; - break; - default: - $level_tips = 'Unkonw Type Error: '; - break; - } - $error = $level_tips . $error_msg . ' in ' . $error_file . ' on ' . $error_line; - Console::warning($error); + $tips = [ + E_WARNING => ['PHP Warning: ', 'warning'], + E_NOTICE => ['PHP Notice: ', 'notice'], + E_USER_ERROR => ['PHP Error: ', 'error'], + E_USER_WARNING => ['PHP Warning: ', 'warning'], + E_USER_NOTICE => ['PHP Notice: ', 'notice'], + E_STRICT => ['PHP Strict: ', 'notice'], + E_RECOVERABLE_ERROR => ['PHP Recoverable Error: ', 'error'], + E_DEPRECATED => ['PHP Deprecated: ', 'notice'], + E_USER_DEPRECATED => ['PHP User Deprecated: ', 'notice'], + ]; + $level_tip = $tips[$error_no] ?? ['PHP Unknown: ', 'error']; + $error = $level_tip[0] . $error_msg . ' in ' . $error_file . ' on ' . $error_line; + logger()->{$level_tip}[1]($error); // 如果 return false 则错误会继续递交给 PHP 标准错误处理 return true; }, E_ALL | E_STRICT); @@ -377,10 +355,10 @@ class Framework self::$server->start(); zm_atomic('server_is_stopped')->set(1); if (!self::$argv['private-mode']) { - Console::log('zhamao-framework is stopped.'); + logger()->info('炸毛框架已停止!'); } } catch (Throwable $e) { - exit(zm_internal_errcode('E00011') . 'Framework has an uncaught ' . get_class($e) . ': ' . $e->getMessage() . PHP_EOL); + exit(zm_internal_errcode('E00011') . '框架发生未捕获的异常:' . get_class($e) . ': ' . $e->getMessage() . PHP_EOL); } } @@ -443,12 +421,12 @@ class Framework $r = exec(PHP_BINARY . ' ' . DataProvider::getFrameworkRootDir() . '/src/ZM/script_setup_loader.php', $output, $result_code); } if ($result_code !== 0) { - Console::error('Parsing code error!'); + logger()->emergency('代码解析错误!'); exit(1); } $json = json_decode($r, true); if (!is_array($json)) { - Console::warning(zm_internal_errcode('E00012') . 'Parsing @SwooleHandler and @OnSetup error!'); + logger()->error(zm_internal_errcode('E00012') . '解析 @SwooleHandler 及 @OnSetup 时发生错误,请检查代码!'); } $this->setup_events = $json; } @@ -477,7 +455,7 @@ class Framework } foreach (($this->setup_events['setup'] ?? []) as $v) { - Console::debug('Calling @OnSetup: ' . $v['class']); + logger()->debug('Calling @OnSetup: ' . $v['class']); $c = ZMUtil::getModInstance($v['class']); $method = $v['method']; $c->{$method}(); diff --git a/src/ZM/global_functions.php b/src/ZM/global_functions.php index a76cd0aa..66e4ea98 100644 --- a/src/ZM/global_functions.php +++ b/src/ZM/global_functions.php @@ -790,5 +790,8 @@ function is_assoc_array(array $array): bool */ function logger(): LoggerInterface { + if (!app()->has(LoggerInterface::class)) { + return zm_config('logging.logger')(); + } return resolve(LoggerInterface::class); } From fa6af88566eeb9c2846a8edfb70fe194d6784faa Mon Sep 17 00:00:00 2001 From: sunxyw Date: Sun, 22 May 2022 22:23:31 +0800 Subject: [PATCH 4/5] fix dynamic logger call --- src/ZM/Framework.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ZM/Framework.php b/src/ZM/Framework.php index 378cfe90..c84d5069 100644 --- a/src/ZM/Framework.php +++ b/src/ZM/Framework.php @@ -313,7 +313,7 @@ class Framework ]; $level_tip = $tips[$error_no] ?? ['PHP Unknown: ', 'error']; $error = $level_tip[0] . $error_msg . ' in ' . $error_file . ' on ' . $error_line; - logger()->{$level_tip}[1]($error); + logger()->{$level_tip[1]}($error); // 如果 return false 则错误会继续递交给 PHP 标准错误处理 return true; }, E_ALL | E_STRICT); From 782e668abf754c7e0ae748bc412a203e76677fe2 Mon Sep 17 00:00:00 2001 From: sunxyw Date: Mon, 23 May 2022 11:44:21 +0800 Subject: [PATCH 5/5] improve remote terminal logging --- config/logging.php | 12 +++++--- src/ZM/Framework.php | 60 ++++++++++++++++++------------------- src/ZM/global_functions.php | 14 +++++++-- 3 files changed, 50 insertions(+), 36 deletions(-) diff --git a/config/logging.php b/config/logging.php index 80f0e458..aae5cf16 100644 --- a/config/logging.php +++ b/config/logging.php @@ -8,12 +8,16 @@ use ZM\Logger\ConsoleLogger; return [ 'level' => LogLevel::DEBUG, - 'logger' => static function (): LoggerInterface { - // 在 Master 中,worker_id 将不存在 - $worker_id = app()->has('worker_id') ? '#' . app('worker_id') : 'Master'; + 'logger' => static function (string $title = null): LoggerInterface { + if ($title) { + $title = strtoupper($title); + } else { + // 在 Master 中,worker_id 将不存在 + $title = app()->has('worker_id') ? '#' . app('worker_id') : 'MST'; + } $logger = new ConsoleLogger(zm_config('logging.level')); - $logger::$format = "[%date%] [%level%] [{$worker_id}] %body%"; + $logger::$format = "[%date%] [%level%] [{$title}] %body%"; $logger::$date_format = 'Y-m-d H:i:s'; // 如果你喜欢旧版的日志格式,请取消下行注释 // $logger::$date_format = 'm-d H:i:s'; diff --git a/src/ZM/Framework.php b/src/ZM/Framework.php index c84d5069..8ea534c2 100644 --- a/src/ZM/Framework.php +++ b/src/ZM/Framework.php @@ -191,19 +191,24 @@ class Framework 'port' => 20002, 'token' => '', ]; - $welcome_msg = Console::setColor('Welcome! You can use `help` for usage.', 'green'); + + $welcome_msg = capture_output([logger('trm'), 'info'], ['欢迎使用炸毛远程终端!输入 `help` 查看帮助!']); + $motd = capture_output(function () { + $this->printMotd(); + }); + /** @var Port $port */ $port = self::$server->listen($conf['host'], $conf['port'], SWOOLE_SOCK_TCP); $port->set([ 'open_http_protocol' => false, ]); - $port->on('connect', function (\Swoole\Server $serv, $fd) use ($welcome_msg, $conf) { + $port->on('connect', function (\Swoole\Server $serv, $fd) use ($welcome_msg, $conf, $motd) { ManagerGM::pushConnect($fd, 'terminal'); // 推送欢迎信息 - $serv->send($fd, file_get_contents(working_dir() . '/config/motd.txt')); + $serv->send($fd, $motd); // 要求输入令牌 if (!empty($conf['token'])) { - $serv->send($fd, 'Please input token: '); + $serv->send($fd, '请输入令牌:'); } else { $serv->send($fd, $welcome_msg . "\n>>> "); } @@ -213,38 +218,36 @@ class Framework ob_start(); try { $arr = LightCacheInside::get('light_array', 'input_token') ?? []; - if (empty($arr[$fd] ?? '')) { - if ($conf['token'] != '') { - $token = trim($data); - if ($token === $conf['token']) { - SpinLock::transaction('input_token', function () use ($fd, $token) { - $arr = LightCacheInside::get('light_array', 'input_token'); - $arr[$fd] = $token; - LightCacheInside::set('light_array', 'input_token', $arr); - }); - $serv->send($fd, Console::setColor("Auth success!!\n", 'green')); - $serv->send($fd, $welcome_msg . "\n>>> "); - } else { - $serv->send($fd, Console::setColor("Auth failed!!\n", 'red')); - $serv->close($fd); - } - return; + if (empty($arr[$fd] ?? '') && $conf['token'] !== '') { + $token = trim($data); + if ($token === $conf['token']) { + SpinLock::transaction('input_token', static function () use ($fd, $token) { + $arr = LightCacheInside::get('light_array', 'input_token'); + $arr[$fd] = $token; + LightCacheInside::set('light_array', 'input_token', $arr); + }); + $serv->send($fd, capture_output([logger('trm'), 'info'], ['令牌验证成功!'])); + $serv->send($fd, $welcome_msg . "\n>>> "); + } else { + $serv->send($fd, capture_output([logger('trm'), 'error'], ['令牌验证失败!'])); + $serv->close($fd); } + return; } - if (trim($data) == 'exit' || trim($data) == 'q') { - $serv->send($fd, Console::setColor("Bye!\n", 'blue')); + if (trim($data) === 'exit' || trim($data) === 'q') { + $serv->send($fd, capture_output([logger('trm'), 'info'], ['再见!'])); $serv->close($fd); return; } Terminal::executeCommand(trim($data)); } catch (Exception $e) { $error_msg = $e->getMessage() . ' at ' . $e->getFile() . '(' . $e->getLine() . ')'; - Console::error(zm_internal_errcode('E00009') . 'Uncaught exception ' . get_class($e) . ' when calling "open": ' . $error_msg); - Console::trace(); + logger('trm')->error(zm_internal_errcode('E00009') . 'Uncaught exception ' . get_class($e) . ' when calling "open": ' . $error_msg); + logger('trm')->error($e->getTraceAsString()); } catch (Error $e) { $error_msg = $e->getMessage() . ' at ' . $e->getFile() . '(' . $e->getLine() . ')'; - Console::error(zm_internal_errcode('E00009') . 'Uncaught ' . get_class($e) . ' when calling "open": ' . $error_msg); - Console::trace(); + logger('trm')->error(zm_internal_errcode('E00009') . 'Uncaught ' . get_class($e) . ' when calling "open": ' . $error_msg); + logger('trm')->error($e->getTraceAsString()); } $r = ob_get_clean(); @@ -258,7 +261,6 @@ class Framework $port->on('close', function ($serv, $fd) { ManagerGM::popConnect($fd); - // echo "Client: Close.\n"; }); } @@ -278,9 +280,6 @@ class Framework Runtime::enableCoroutine(false, SWOOLE_HOOK_ALL); } - global $asd; - $asd = get_included_files(); - // 注册 Swoole Server 的事件 $this->registerServerEvents(); @@ -571,6 +570,7 @@ class Framework /** * 更换数组键名 + * * @param mixed $old_key * @param mixed $new_key */ diff --git a/src/ZM/global_functions.php b/src/ZM/global_functions.php index 66e4ea98..d41c5b5a 100644 --- a/src/ZM/global_functions.php +++ b/src/ZM/global_functions.php @@ -788,10 +788,20 @@ function is_assoc_array(array $array): bool /** * 返回 Logger 实例 */ -function logger(): LoggerInterface +function logger(...$args): LoggerInterface { if (!app()->has(LoggerInterface::class)) { - return zm_config('logging.logger')(); + return zm_config('logging.logger')(...$args); } return resolve(LoggerInterface::class); } + +/** + * 捕获输出 + */ +function capture_output(callable $callback, array $args = []): string +{ + ob_start(); + $callback(...$args); + return ob_get_clean(); +}