From ac177c73df39aa909ea50b6ee94435d901365fe4 Mon Sep 17 00:00:00 2001 From: qing <1776177662@qq.com> Date: Mon, 10 Aug 2026 03:19:00 +0800 Subject: [PATCH] =?UTF-8?q?feat(fsys):=20CLI=20=E5=8F=82=E6=95=B0=E6=A0=87?= =?UTF-8?q?=E5=87=86=E5=8C=96=20=E2=80=94=20--host/--log-level/--instance/?= =?UTF-8?q?--config/--help?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 --host 作为 --addr 的规范化别名(两者完全等价) - 新增 --log-level debug|info|warn|error,实现日志级别过滤 * _log() 按 Config.log_level 过滤,低于设定级别的日志直接丢弃 * 兼容现有大写 level 字符串(INFO/WARNING/ERROR) - 新增 --instance 指定实例名(注册中心用,默认 fsys) - 新增 --config 覆盖 confs 拉取的配置名(默认 static.ini) - 新增 --help/-h 打印用法并退出 - Config 优先级不变:CLI > env > confs > 默认值 - 更新启动输出包含 instance/log-level/config 信息 --- fsys/src/fsys.cpp | 76 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 70 insertions(+), 6 deletions(-) diff --git a/fsys/src/fsys.cpp b/fsys/src/fsys.cpp index d3eece8..b8723cf 100644 --- a/fsys/src/fsys.cpp +++ b/fsys/src/fsys.cpp @@ -14,7 +14,7 @@ * 安全改进(相比 Python static): * F-1 server.setMaxBodySize(10MB) 限制请求体大小 * F-2 libhttp 原生 HTTPS 支持,无需回退开发服务器 - * F-3 命令行参数 --addr/-a --port/-p --threads/-t + * F-3 命令行参数 --host/--addr/-a --port/-p --threads/-t --log-level --instance --config --help * F-4 所有端口/线程数有严格边界校验 * F-5 Boost.Beast 异步多线程替代 Flask 同步 * F-6 消除 Python/Flask/waitress 依赖 @@ -271,11 +271,40 @@ struct Config { int db_port = 8005; std::string dnfs_url = "http://127.0.0.1:8006"; + + // CLI 标准化参数(Step 3) + std::string log_level = "info"; // debug|info|warn|error + std::string instance_name = "fsys"; // 实例名(注册中心用) + std::string confs_config_name = "static.ini"; // confs 拉取的配置名 }; static Config load_config(int argc, char* argv[]) { Config cfg; + // 0. 预扫描 --help 和 --config(需在 confs 拉取前处理) + for (int i = 1; i < argc; ++i) { + std::string arg = argv[i]; + if (arg == "--help" || arg == "-h") { + std::printf( + "fsys — C++20 静态文件托管服务\n\n" + "Usage: fsys [OPTIONS]\n\n" + "Options:\n" + " -h, --help Show this help and exit\n" + " -a, --addr Listen address (alias: --host)\n" + " --host Listen address (canonical name)\n" + " -p, --port Listen port\n" + " -t, --threads Worker threads\n" + " --config confs config name (default: static.ini)\n" + " --log-level debug|info|warn|error (default: info)\n" + " --instance Instance name (default: fsys)\n\n" + "Config priority: CLI > env > confs > defaults\n"); + std::exit(0); + } + if (arg == "--config" && i + 1 < argc) { + cfg.confs_config_name = argv[++i]; + } + } + // 1. confs 引导地址 if (const char* h = std::getenv("CONFS_HOST")) cfg.confs_host = h; if (const char* p = std::getenv("CONFS_PORT")) { @@ -286,17 +315,18 @@ static Config load_config(int argc, char* argv[]) { } } - // 2. 从 confs 拉取 static.ini(retry_on_refused=true) + // 2. 从 confs 拉取配置(retry_on_refused=true) std::string ini_text; try { RpcClient confs_client(cfg.confs_host, cfg.confs_port, "fsys", /*timeout=*/5.0, /*retry_on_refused=*/true); - json::value data = confs_client.call("get", {{"name", "static.ini"}}); + json::value data = confs_client.call("get", {{"name", cfg.confs_config_name}}); if (data.is_object() && data.as_object().contains("content")) { ini_text = std::string(data.as_object().at("content").as_string()); } } catch (const std::exception& e) { - std::fprintf(stderr, "[fsys] 从 confs 获取 static.ini 失败: %s\n", e.what()); + std::fprintf(stderr, "[fsys] 从 confs 获取 %s 失败: %s\n", + cfg.confs_config_name.c_str(), e.what()); std::exit(1); } @@ -343,9 +373,12 @@ static Config load_config(int argc, char* argv[]) { // 5. 命令行参数(最高优先级) for (int i = 1; i < argc; ++i) { std::string arg = argv[i]; - if ((arg == "--addr" || arg == "-a") && i + 1 < argc) cfg.listen_host = argv[++i]; + if ((arg == "--addr" || arg == "-a" || arg == "--host") && i + 1 < argc) cfg.listen_host = argv[++i]; else if ((arg == "--port" || arg == "-p") && i + 1 < argc) cfg.listen_port = safe_stoi(argv[++i], "--port"); else if ((arg == "--threads" || arg == "-t") && i + 1 < argc) cfg.threads = safe_stoi(argv[++i], "--threads"); + else if (arg == "--log-level" && i + 1 < argc) cfg.log_level = argv[++i]; + else if (arg == "--instance" && i + 1 < argc) cfg.instance_name = argv[++i]; + // --config 和 --help 已在预扫描阶段处理 } // 6. 校验必需配置项 @@ -372,6 +405,18 @@ static Config load_config(int argc, char* argv[]) { std::exit(1); } + // log_level 校验 + { + std::string ll = cfg.log_level; + std::transform(ll.begin(), ll.end(), ll.begin(), ::tolower); + if (ll != "debug" && ll != "info" && ll != "warn" && ll != "error") { + std::fprintf(stderr, "[fsys] invalid --log-level: %s (must be debug|info|warn|error)\n", + cfg.log_level.c_str()); + std::exit(1); + } + cfg.log_level = ll; + } + // 8. 路径规范化:static_root/SSL 相对路径基于当前工作目录 // (_run.sh 以模块目录为 cwd 启动,与 Python 版 BASE_DIR 语义一致; // Docker 场景使用绝对路径 STATIC_ROOT,不受影响) @@ -654,8 +699,11 @@ public: _filesystem_enabled = false; } - std::printf("[fsys] 配置来源: confs (static.ini @ %s:%d)\n", + std::printf("[fsys] 配置来源: confs (%s @ %s:%d)\n", + _cfg.confs_config_name.c_str(), _cfg.confs_host.c_str(), _cfg.confs_port); + std::printf("[fsys] 实例: %s | 日志级别: %s\n", + _cfg.instance_name.c_str(), _cfg.log_level.c_str()); std::printf("[fsys] 静态目录: %s\n", _cfg.static_root.c_str()); } @@ -687,6 +735,19 @@ private: void _log(const std::string& level, const std::string& service, const std::string& message, const std::string& trace_id = "", const std::string& extra = "") { + // 日志级别过滤 + static const std::unordered_map kLogLevels = { + {"debug", 0}, {"DEBUG", 0}, + {"info", 1}, {"INFO", 1}, + {"warn", 2}, {"WARNING", 2}, + {"error", 3}, {"ERROR", 3} + }; + auto cfg_it = kLogLevels.find(_cfg.log_level); + auto msg_it = kLogLevels.find(level); + if (cfg_it != kLogLevels.end() && msg_it != kLogLevels.end()) { + if (msg_it->second < cfg_it->second) return; + } + LogEntry e; e.ts = utc_now(); e.service = service; @@ -1576,6 +1637,9 @@ int main(int argc, char* argv[]) { cfg.static_root.c_str(), cfg.ssl_enabled ? "on" : "off"); std::printf("[fsys] db=%s:%d dnfs=%s\n", cfg.db_host.c_str(), cfg.db_port, cfg.dnfs_url.c_str()); + std::printf("[fsys] instance=%s log-level=%s config=%s\n", + cfg.instance_name.c_str(), cfg.log_level.c_str(), + cfg.confs_config_name.c_str()); std::fflush(stdout); FsysServer server(std::move(cfg));