diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a0f5c0436..41766c34df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,12 @@ This section accumulates work toward the **2.3.0** milestone ### Fixed +- **dev:** `scripts/dev_multi_instance.sh logs all` now prints the nginx logs + as well as both Gateway logs; it printed only the Gateway logs, the same as + `logs` with no argument. `logs nginx` and `logs all` also include `nginx.log`, + the nginx start command's own output, which no option printed before. + ([#7723]) + - **memory:** `GET /api/memory/config` and `/api/memory/status` now mask credential values in `backend_config` (`api_key`, tokens, passwords, `Authorization` headers, at any depth) as `***`. They returned the config as @@ -15927,3 +15933,4 @@ with **180 merged pull requests** since the first 2.0 milestone tag. [#7651]: https://github.com/bytedance/deer-flow/pull/7651 [#7659]: https://github.com/bytedance/deer-flow/pull/7659 [#7665]: https://github.com/bytedance/deer-flow/pull/7665 +[#7723]: https://github.com/bytedance/deer-flow/pull/7723 diff --git a/CHANGELOG_zh.md b/CHANGELOG_zh.md index 7f6d1fc9b1..a87009dbee 100644 --- a/CHANGELOG_zh.md +++ b/CHANGELOG_zh.md @@ -14,6 +14,11 @@ ### 修复 +- **开发:** `scripts/dev_multi_instance.sh logs all` 现在除两个 Gateway 日志外也会输出 + nginx 日志;此前它只输出 Gateway 日志,与不带参数的 `logs` 相同。`logs nginx` 与 + `logs all` 还会包含 `nginx.log`(nginx 启动命令自身的输出),此前没有任何选项会输出它。 + ([#7723]) + - **记忆:** `GET /api/memory/config` 与 `/api/memory/status` 现在会把 `backend_config` 中的凭据值(`api_key`、token、密码、`Authorization` 请求头,任意层级)遮蔽为 `***`。 此前它们按加载结果原样返回配置,而 `$VAR` 引用此时已被解析,因此 DeerMem 提取模型的密钥 @@ -12695,3 +12700,4 @@ DeerFlow 2.0 是围绕"超级智能体"框架的彻底重写,核心包含子 [#7651]: https://github.com/bytedance/deer-flow/pull/7651 [#7659]: https://github.com/bytedance/deer-flow/pull/7659 [#7665]: https://github.com/bytedance/deer-flow/pull/7665 +[#7723]: https://github.com/bytedance/deer-flow/pull/7723 diff --git a/backend/docs/CONFIGURATION.md b/backend/docs/CONFIGURATION.md index ffd724b1a5..8b885b4857 100644 --- a/backend/docs/CONFIGURATION.md +++ b/backend/docs/CONFIGURATION.md @@ -813,7 +813,7 @@ Notes: scripts/dev_multi_instance.sh up # containers, config, Gateway A, then B, then nginx scripts/dev_multi_instance.sh check # automated cross-instance checks (below) scripts/dev_multi_instance.sh stop b --kill # SIGKILL B to simulate a crash; `start b` brings it back -scripts/dev_multi_instance.sh logs a -f +scripts/dev_multi_instance.sh logs a -f # follow Gateway A; also b, nginx, or all (both Gateways and nginx) scripts/dev_multi_instance.sh down ``` diff --git a/backend/tests/test_dev_multi_instance_script.py b/backend/tests/test_dev_multi_instance_script.py index 654ea7937c..d05666ce2f 100644 --- a/backend/tests/test_dev_multi_instance_script.py +++ b/backend/tests/test_dev_multi_instance_script.py @@ -607,6 +607,47 @@ def test_shell_script_rejects_unknown_commands(tmp_path): assert "Unknown command" in result.stderr +_GATEWAY_LOGS = ("gateway-a.log", "gateway-b.log") +_NGINX_LOGS = ("nginx.log", "nginx-error.log", "nginx-access.log") + + +@pytest.mark.parametrize( + ("args", "expected"), + [((), _GATEWAY_LOGS), (("b",), ("gateway-b.log",)), (("nginx",), _NGINX_LOGS), (("all",), _GATEWAY_LOGS + _NGINX_LOGS)], + ids=["default", "b", "nginx", "all"], +) +def test_shell_script_logs_prints_the_selected_files(tmp_path, args, expected): + logs = tmp_path / "state" / "logs" + logs.mkdir(parents=True) + for name in _GATEWAY_LOGS + _NGINX_LOGS: + (logs / name).write_text(f"line from {name}\n", encoding="utf-8") + env = {**os.environ, "DEERFLOW_MI_STATE_DIR": str(tmp_path / "state")} + + result = subprocess.run([require_script_bash(), str(SHELL_PATH), "logs", *args], capture_output=True, text=True, timeout=30, env=env) + + assert result.returncode == 0, result.stderr + headers = [line.removeprefix("==> ").removesuffix(" <==") for line in result.stdout.splitlines() if line.startswith("==> ")] + assert [Path(header).name for header in headers] == list(expected) + for name in expected: + assert f"line from {name}" in result.stdout + + +@pytest.mark.parametrize(("args", "expected"), [(("all",), _GATEWAY_LOGS), (("nginx",), ())], ids=["all", "nginx"]) +def test_shell_script_logs_skips_nginx_files_when_nginx_never_started(tmp_path, args, expected): + # start_nginx bails on a missing binary or busy port, leaving only Gateway logs. + logs = tmp_path / "state" / "logs" + logs.mkdir(parents=True) + for name in _GATEWAY_LOGS: + (logs / name).write_text(f"line from {name}\n", encoding="utf-8") + env = {**os.environ, "DEERFLOW_MI_STATE_DIR": str(tmp_path / "state")} + + result = subprocess.run([require_script_bash(), str(SHELL_PATH), "logs", *args], capture_output=True, text=True, timeout=30, env=env) + + assert result.returncode == 0, result.stderr + headers = [line.removeprefix("==> ").removesuffix(" <==") for line in result.stdout.splitlines() if line.startswith("==> ")] + assert [Path(header).name for header in headers] == list(expected) + + def test_makefile_exposes_harness_targets(): makefile = (REPO_ROOT / "Makefile").read_text(encoding="utf-8") diff --git a/scripts/dev_multi_instance.sh b/scripts/dev_multi_instance.sh index 830679d8a6..91850f1cd6 100755 --- a/scripts/dev_multi_instance.sh +++ b/scripts/dev_multi_instance.sh @@ -59,7 +59,7 @@ Commands: up [--skip-install] [--no-nginx] Start containers, render the config, start A, then B, then nginx down Stop everything; delete the containers and harness data (logs are kept) status Show containers, Gateways and nginx - logs [a|b|nginx|all] [-f] Print the last 100 log lines (-f follows) + logs [a|b|nginx|all] [-f] Print the last 100 log lines (default a and b; all adds nginx; -f follows) check [--with-llm] Run the cross-instance checks against the running pair stop [--kill] Stop one Gateway (SIGTERM; --kill sends SIGKILL to simulate a crash) start Start a stopped Gateway again @@ -579,12 +579,13 @@ cmd_status() { } cmd_logs() { - local follow=false arg files="" + # nginx.log holds what the nginx command printed while starting. + local follow=false arg files="" nginx_logs="nginx.log nginx-error.log nginx-access.log" for arg in "$@"; do case "$arg" in a | b) files="$files gateway-$arg.log" ;; - nginx) files="$files nginx-error.log nginx-access.log" ;; - all) files="$files gateway-a.log gateway-b.log" ;; + nginx) files="$files $nginx_logs" ;; + all) files="$files gateway-a.log gateway-b.log $nginx_logs" ;; -f | --follow) follow=true ;; *) die "Unknown option for logs: $arg" ;; esac