mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-09-22 12:36:26 +00:00
fix(docker): add 'make prod-logs' entry point and hint when dev logs are empty (#5538)
* fix(docker): add 'make prod-logs' entry point and hint when dev logs are empty `make up` starts the production stack (deploy.sh: project `deer-flow`, docker/docker-compose.yaml) while `make docker-logs` tails the dev stack (project `deer-flow-dev`, docker-compose-dev.yaml), so after `make up` it printed nothing (#5529), and no make entry point showed production logs at all. - scripts/docker.sh logs gains `--prod`: targets the stack deploy.sh started, passes --env-file ../.env when present, and exports the same interpolation defaults deploy.sh exports before every compose call — without them the production volume specs fail to parse on checkouts without .env. - dev-only `logs` with no running containers now prints a hint pointing at `make prod-logs` instead of staying silent. - Makefile gains `prod-logs`, listed under Docker Production Commands. New tests cover production targeting and the empty-state hint; they are red on unfixed main and green here. Verified live: with a deer-flow redis running, `logs --prod --redis` streams its logs. Fixes #5529 * fix(docker): append --env-file after compose detection rebuilds COMPOSE_CMD compose_preflight() probes the Compose binary and rebuilds COMPOSE_CMD, so an --env-file appended before it was silently dropped. Append it after preflight instead, and drive the regression test through the real detection path (stub Docker Compose version v5.3.1, not require_compose_version) so the append cannot regress silently. Reviewed-in: #5538
This commit is contained in:
parent
82cf57a9c3
commit
859b105b40
7
Makefile
7
Makefile
@ -1,6 +1,6 @@
|
||||
# DeerFlow - Unified Development Environment
|
||||
|
||||
.PHONY: help config config-upgrade check check-agent-guidance install extension-install extension-upgrade extension-list extension-enable extension-disable extension-remove setup doctor support-bundle detect-thread-boundaries detect-blocking-io dev dev-daemon start start-daemon nginx stop up down clean docker-init docker-start docker-stop docker-logs docker-logs-frontend docker-logs-gateway docker-logs-redis setup-sandbox
|
||||
.PHONY: help config config-upgrade check check-agent-guidance install extension-install extension-upgrade extension-list extension-enable extension-disable extension-remove setup doctor support-bundle detect-thread-boundaries detect-blocking-io dev dev-daemon start start-daemon nginx stop up down prod-logs clean docker-init docker-start docker-stop docker-logs docker-logs-frontend docker-logs-gateway docker-logs-redis setup-sandbox
|
||||
|
||||
BASH ?= bash
|
||||
BACKEND_UV_RUN = cd backend && uv run
|
||||
@ -50,6 +50,7 @@ help:
|
||||
@echo ""
|
||||
@echo "Docker Production Commands:"
|
||||
@echo " make up - Build and start production Docker services (localhost:2026)"
|
||||
@echo " make prod-logs - Follow production Docker logs (stack started by 'make up')"
|
||||
@echo " make down - Stop and remove production Docker containers"
|
||||
@echo ""
|
||||
@echo "Docker Development Commands:"
|
||||
@ -217,3 +218,7 @@ up:
|
||||
# Stop and remove production containers
|
||||
down:
|
||||
@$(RUN_SHELL_SCRIPT) ./scripts/deploy.sh down
|
||||
|
||||
# Follow production container logs (stack started by `make up`)
|
||||
prod-logs:
|
||||
@$(RUN_SHELL_SCRIPT) ./scripts/docker.sh logs --prod
|
||||
|
||||
@ -313,6 +313,83 @@ require_compose_version
|
||||
assert "too old" in result.stdout
|
||||
|
||||
|
||||
@pytest.mark.parametrize("args", ["logs --prod", "logs --prod --gateway"])
|
||||
def test_logs_prod_targets_production_stack(args):
|
||||
"""`logs --prod` must tail the stack deploy.sh started, not the dev project.
|
||||
|
||||
`make up` runs scripts/deploy.sh (project `deer-flow`, docker-compose.yaml)
|
||||
while the dev default is project `deer-flow-dev`, so `make docker-logs`
|
||||
after `make up` printed nothing (#5529). The production entry point must
|
||||
target the same project and interpolate the same .env.
|
||||
|
||||
Compose detection is NOT stubbed here: it rebuilds COMPOSE_CMD, and the
|
||||
appended `--env-file` must survive that rebuild (#5538 review).
|
||||
"""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
tmp_root = Path(tmpdir)
|
||||
(tmp_root / "docker-compose.yaml").write_text("services: {}\n", encoding="utf-8")
|
||||
(tmp_root / ".env").write_text("KEEP=me\n", encoding="utf-8")
|
||||
marker = tmp_root / "prod_invoke.txt"
|
||||
|
||||
command = f"""
|
||||
source '{SCRIPT_PATH}'
|
||||
PROJECT_ROOT='{tmp_root}'
|
||||
DOCKER_DIR='{tmp_root}'
|
||||
docker() {{
|
||||
if [ "$1" = compose ] && [ "$2" = version ]; then
|
||||
echo '2.41.0'
|
||||
return 0
|
||||
fi
|
||||
if [ "$1" = compose ]; then
|
||||
printf '%s\\n' "$*" "DEER_FLOW_HOME=${{DEER_FLOW_HOME:-unset}}" > '{marker}'
|
||||
return 0
|
||||
fi
|
||||
command docker "$@"
|
||||
}}
|
||||
unset DEER_FLOW_ROOT DEER_FLOW_HOME DEER_FLOW_CONFIG_PATH
|
||||
unset DEER_FLOW_EXTENSIONS_CONFIG_PATH DEER_FLOW_REPO_ROOT
|
||||
unset BETTER_AUTH_SECRET DEER_FLOW_INTERNAL_AUTH_TOKEN
|
||||
{args}
|
||||
"""
|
||||
subprocess.check_call([BASH_EXECUTABLE, "-lc", command])
|
||||
|
||||
recorded = marker.read_text(encoding="utf-8")
|
||||
assert "-p deer-flow " in recorded, recorded
|
||||
assert "-f docker-compose.yaml" in recorded, recorded
|
||||
assert "--env-file ../.env" in recorded, recorded
|
||||
assert "logs" in recorded, recorded
|
||||
# deploy.sh exports interpolation defaults before every compose call;
|
||||
# `logs --prod` must too, or the volume specs fail to parse.
|
||||
assert "DEER_FLOW_HOME=" in recorded, recorded
|
||||
assert "DEER_FLOW_HOME=unset" not in recorded, recorded
|
||||
|
||||
|
||||
def test_logs_without_dev_containers_hints_at_prod_logs():
|
||||
"""Silent empty output is the #5529 report: point at the production entry point."""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
tmp_root = Path(tmpdir)
|
||||
_seed_compose_file(tmp_root)
|
||||
|
||||
command = f"""
|
||||
source '{SCRIPT_PATH}'
|
||||
PROJECT_ROOT='{tmp_root}'
|
||||
DOCKER_DIR='{tmp_root}'
|
||||
require_compose_version() {{ :; }}
|
||||
COMPOSE_CMD=true
|
||||
unset DEER_FLOW_ROOT
|
||||
logs
|
||||
"""
|
||||
result = subprocess.run(
|
||||
[BASH_EXECUTABLE, "-lc", command],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
assert result.returncode == 0, result.stdout + result.stderr
|
||||
assert "make prod-logs" in result.stdout
|
||||
|
||||
|
||||
def test_aio_dood_socket_preflight_allows_windows_when_docker_reachable():
|
||||
"""Windows Git Bash without /var/run/docker.sock proceeds when Docker daemon is reachable."""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
|
||||
@ -16,12 +16,15 @@ DOCKER_DIR="$PROJECT_ROOT/docker"
|
||||
# Use a filename relative to DOCKER_DIR (we always `cd` there) so Windows
|
||||
# Docker Desktop does not receive a Git Bash `/c/...` path it cannot open.
|
||||
COMPOSE_FILE="docker-compose-dev.yaml"
|
||||
# Dev stack project name. `logs --prod` swaps both values for the production
|
||||
# stack started by `make up` (scripts/deploy.sh: project `deer-flow`).
|
||||
COMPOSE_PROJECT="deer-flow-dev"
|
||||
# Selected by require_compose_version: prefer the V2 plugin, else hyphenated binary.
|
||||
# Kept as an array so "docker compose" stays two words under set -u / quoting.
|
||||
COMPOSE_BIN=(docker compose)
|
||||
|
||||
_refresh_compose_cmd() {
|
||||
COMPOSE_CMD="${COMPOSE_BIN[*]} -p deer-flow-dev -f ${COMPOSE_FILE}"
|
||||
COMPOSE_CMD="${COMPOSE_BIN[*]} -p ${COMPOSE_PROJECT} -f ${COMPOSE_FILE}"
|
||||
}
|
||||
_refresh_compose_cmd
|
||||
|
||||
@ -416,43 +419,73 @@ start() {
|
||||
echo ""
|
||||
}
|
||||
|
||||
# View Docker development logs
|
||||
# View Docker logs. The dev stack (make docker-start) is the default;
|
||||
# `--prod` tails the production stack started by `make up` (scripts/deploy.sh).
|
||||
logs() {
|
||||
local service=""
|
||||
local is_prod=0
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--prod)
|
||||
is_prod=1
|
||||
;;
|
||||
--frontend|--gateway|--nginx|--redis|--provisioner)
|
||||
if [ -n "$service" ]; then
|
||||
echo -e "${YELLOW}Only one service option is allowed (got --$service and $1).${NC}"
|
||||
exit 1
|
||||
fi
|
||||
service="${1#--}"
|
||||
;;
|
||||
*)
|
||||
echo -e "${YELLOW}Unknown option: $1${NC}"
|
||||
echo "Usage: $0 logs [--prod] [--frontend|--gateway|--nginx|--redis|--provisioner]"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [ "$is_prod" = 1 ]; then
|
||||
# Target the same project deploy.sh started. Relative paths: this
|
||||
# runs with cwd=$DOCKER_DIR.
|
||||
COMPOSE_FILE="docker-compose.yaml"
|
||||
COMPOSE_PROJECT="deer-flow"
|
||||
# deploy.sh exports these before every compose invocation so the
|
||||
# volume specs in docker-compose.yaml interpolate; without them even
|
||||
# `logs` fails to parse the file on checkouts without a .env.
|
||||
export DEER_FLOW_HOME="${DEER_FLOW_HOME:-$PROJECT_ROOT/backend/.deer-flow}"
|
||||
export DEER_FLOW_CONFIG_PATH="${DEER_FLOW_CONFIG_PATH:-$DEER_FLOW_HOME/config.yaml}"
|
||||
export DEER_FLOW_EXTENSIONS_CONFIG_PATH="${DEER_FLOW_EXTENSIONS_CONFIG_PATH:-$DEER_FLOW_HOME/extensions_config.json}"
|
||||
export DEER_FLOW_REPO_ROOT="${DEER_FLOW_REPO_ROOT:-$PROJECT_ROOT}"
|
||||
export BETTER_AUTH_SECRET="${BETTER_AUTH_SECRET:-placeholder}"
|
||||
export DEER_FLOW_INTERNAL_AUTH_TOKEN="${DEER_FLOW_INTERNAL_AUTH_TOKEN:-placeholder}"
|
||||
elif [ -z "$service" ]; then
|
||||
# The dev and production stacks use different compose projects, so
|
||||
# `make docker-logs` after `make up` would exit with empty output;
|
||||
# point at the production entry point instead of staying silent.
|
||||
if [ -z "$(cd "$DOCKER_DIR" && $COMPOSE_CMD ps -q 2>/dev/null)" ]; then
|
||||
echo -e "${YELLOW}No dev containers are running.${NC}"
|
||||
echo "Started the production stack with 'make up'? View its logs with 'make prod-logs'."
|
||||
fi
|
||||
fi
|
||||
|
||||
compose_preflight
|
||||
|
||||
case "$1" in
|
||||
--frontend)
|
||||
service="frontend"
|
||||
echo -e "${BLUE}Viewing frontend logs...${NC}"
|
||||
;;
|
||||
--gateway)
|
||||
service="gateway"
|
||||
echo -e "${BLUE}Viewing gateway logs...${NC}"
|
||||
;;
|
||||
--nginx)
|
||||
service="nginx"
|
||||
echo -e "${BLUE}Viewing nginx logs...${NC}"
|
||||
;;
|
||||
--redis)
|
||||
service="redis"
|
||||
echo -e "${BLUE}Viewing redis logs...${NC}"
|
||||
;;
|
||||
--provisioner)
|
||||
service="provisioner"
|
||||
echo -e "${BLUE}Viewing provisioner logs...${NC}"
|
||||
;;
|
||||
"")
|
||||
echo -e "${BLUE}Viewing all logs...${NC}"
|
||||
;;
|
||||
*)
|
||||
echo -e "${YELLOW}Unknown option: $1${NC}"
|
||||
echo "Usage: $0 logs [--frontend|--gateway|--nginx|--redis|--provisioner]"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Append --env-file only after compose_preflight(): its Compose detection
|
||||
# may rebuild COMPOSE_CMD, which would drop anything appended before it.
|
||||
if [ "$is_prod" = 1 ] && [ -f "$PROJECT_ROOT/.env" ]; then
|
||||
COMPOSE_CMD="$COMPOSE_CMD --env-file ../.env"
|
||||
fi
|
||||
|
||||
if [ -n "$service" ]; then
|
||||
echo -e "${BLUE}Viewing $service logs...${NC}"
|
||||
elif [ "$is_prod" = 1 ]; then
|
||||
echo -e "${BLUE}Viewing production stack logs...${NC}"
|
||||
else
|
||||
echo -e "${BLUE}Viewing all logs...${NC}"
|
||||
fi
|
||||
|
||||
cd "$DOCKER_DIR" && $COMPOSE_CMD logs -f $service
|
||||
}
|
||||
|
||||
@ -493,7 +526,8 @@ help() {
|
||||
echo " init - Pull the sandbox image (speeds up first Pod startup)"
|
||||
echo " start - Start Docker services (auto-detects sandbox mode from config.yaml)"
|
||||
echo " restart - Restart all running Docker services"
|
||||
echo " logs [option] - View Docker development logs"
|
||||
echo " logs [option] - View Docker logs (dev stack by default, production with --prod)"
|
||||
echo " --prod View production stack logs (containers from 'make up')"
|
||||
echo " --frontend View frontend logs only"
|
||||
echo " --gateway View gateway logs only"
|
||||
echo " --nginx View nginx logs only"
|
||||
@ -518,7 +552,8 @@ main() {
|
||||
restart
|
||||
;;
|
||||
logs)
|
||||
logs "$2"
|
||||
shift
|
||||
logs "$@"
|
||||
;;
|
||||
stop)
|
||||
stop
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user