SERVER-113309 direct bazel wrapper output to a logfile (#43855)

GitOrigin-RevId: 403948b8ec293e41032aef2b5b5685fac00db6db
This commit is contained in:
Daniel Moody 2025-11-17 12:05:10 -06:00 committed by MongoDB Bot
parent d508bd671b
commit cde3170368
3 changed files with 246 additions and 67 deletions

View File

@ -10,10 +10,61 @@ sys.path.append(REPO_ROOT)
from bazel.wrapper_hook.wrapper_debug import wrapper_debug from bazel.wrapper_hook.wrapper_debug import wrapper_debug
def get_terminal_stream(fd_env_var: str):
"""Return a Python file object for the original terminal FD."""
fd_str = os.environ.get(fd_env_var)
if not fd_str:
return None
# Handle Windows CON device
if fd_str == "CON":
# On Windows, open CON device for console output
# Use the appropriate stream based on the variable name
if "STDOUT" in fd_env_var:
try:
return open("CON", "w", buffering=1)
except (OSError, IOError):
return None
elif "STDERR" in fd_env_var:
try:
return open("CON", "w", buffering=1)
except (OSError, IOError):
return None
return None
# Handle Unix file descriptors
if fd_str.isdigit():
fd = int(fd_str)
try:
return os.fdopen(fd, "w", buffering=1)
except (OSError, ValueError):
return None
return None
def setup_auth_wrapper(): def setup_auth_wrapper():
from buildscripts.bazel_rules_mongo.engflow_auth.engflow_auth import setup_auth from buildscripts.bazel_rules_mongo.engflow_auth.engflow_auth import setup_auth
setup_auth(verbose=False) term_out = get_terminal_stream("MONGO_WRAPPER_STDOUT_FD")
term_err = get_terminal_stream("MONGO_WRAPPER_STDERR_FD")
# Save current stdout/stderr
old_stdout = sys.stdout
old_stderr = sys.stderr
try:
if term_out:
sys.stdout = term_out
if term_err:
sys.stderr = term_err
setup_auth(verbose=False)
finally:
# Restore original stdout/stderr to whatever wrapper has
sys.stdout = old_stdout
sys.stderr = old_stderr
def engflow_auth(args): def engflow_auth(args):

View File

@ -119,6 +119,12 @@ done
if [ -z $current_bazel_command ]; then if [ -z $current_bazel_command ]; then
skip_python=1 skip_python=1
fi fi
SLOW_PATH=0
if [[ "$skip_python" == "0" ]]; then
# We'll do wrapper hook / python installation
SLOW_PATH=1
fi
if [ "$skip_python" == "0" ]; then if [ "$skip_python" == "0" ]; then
# known list of commands to skip # known list of commands to skip
@ -133,9 +139,49 @@ if [ "$skip_python" == "0" ]; then
done done
fi fi
if [ "$skip_python" == "1" ]; then if [ "$skip_python" == "1" ]; then
exec "$bazel_real" $@ # Fast path: no wrapper output, run Bazel directly to terminal
fi exec "$bazel_real" "$@"
fi
if [[ "$SLOW_PATH" == "1" ]]; then
ORIGINAL_ARGS=("$@")
# Save original terminal output FDs
exec 3>&1 4>&2
export MONGO_WRAPPER_STDOUT_FD=3
export MONGO_WRAPPER_STDERR_FD=4
LOG_DIR=${MONGO_BAZEL_LOG_DIR:-"$REPO_ROOT/.bazel_logs"}
mkdir -p "$LOG_DIR"
LOGFILE="${LOG_DIR}/bazel_wrapper_$(date +%Y%m%d_%H%M%S)_$$.log"
# Redirect stdout/stderr to logfile
exec >"$LOGFILE" 2>&1
WRAPPER_START_EPOCH=$(date +%s)
GREEN='\033[0;32m'
RED='\033[1;31m'
NO_COLOR='\033[0m'
echo -e "${GREEN}INFO:${NO_COLOR} running wrapper hook..." >&4
print_summary() {
local exit_code=$?
local end_epoch=$(date +%s)
local duration=$(( end_epoch - WRAPPER_START_EPOCH ))
if [[ $exit_code -ne 0 ]]; then
echo -e "${RED}ERROR:${NO_COLOR} wrapper hook failed: " >&4
cat "$LOGFILE" >&4
else
echo "Bazel wrapper finished. Exit code: ${exit_code}. Duration: ${duration}s" >&4
fi
}
trap 'print_summary' EXIT
fi
# find existing python installs # find existing python installs
cur_dir=$(basename $REPO_ROOT) cur_dir=$(basename $REPO_ROOT)
@ -154,11 +200,15 @@ if [[ "$python" = "" ]] || [ ! -f $python ]; then
>&2 echo "python prereq missing, using bazel to install python..." >&2 echo "python prereq missing, using bazel to install python..."
>&2 $bazel_real build --bes_backend= --bes_results_url= @py_${os}_${ARCH}//:all >&2 $bazel_real build --bes_backend= --bes_results_url= @py_${os}_${ARCH}//:all
if [[ $? != 0 ]]; then if [[ $? != 0 ]]; then
if [[ ! -z "$CI" ]] || [[ $MONGO_BAZEL_WRAPPER_FALLBACK == 1 ]]; then >&2 $bazel_real build --config=local @py_${os}_${ARCH}//:all
>&2 echo "wrapper script failed to install python! falling back to normal bazel call..." if [[ $? != 0 ]]; then
exec "$bazel_real" $@ if [[ ! -z "$CI" ]] || [[ $MONGO_BAZEL_WRAPPER_FALLBACK == 1 ]]; then
else >&2 echo "wrapper script failed to install python! falling back to normal bazel call..."
exit $? "$bazel_real" "$@"
exit $?
else
exit $?
fi
fi fi
fi fi
fi fi
@ -201,7 +251,8 @@ fi
if [[ $exit_code != 0 ]]; then if [[ $exit_code != 0 ]]; then
if [[ ! -z "$CI" ]] || [[ $MONGO_BAZEL_WRAPPER_FALLBACK == 1 ]]; then if [[ ! -z "$CI" ]] || [[ $MONGO_BAZEL_WRAPPER_FALLBACK == 1 ]]; then
>&2 echo "wrapper script failed! falling back to normal bazel call..." >&2 echo "wrapper script failed! falling back to normal bazel call..."
exec "$bazel_real" $@ "$bazel_real" "$@"
exit $?
else else
exit $? exit $?
fi fi
@ -221,14 +272,17 @@ if [[ $MONGO_BAZEL_WRAPPER_DEBUG == 1 ]] && [[ $autocomplete_query == 0 ]]; then
>&2 echo "[WRAPPER_HOOK_DEBUG]: wrapper hook script took $runtime seconds" >&2 echo "[WRAPPER_HOOK_DEBUG]: wrapper hook script took $runtime seconds"
fi fi
if [[ $autocomplete_query == 1 ]]; then if [[ $autocomplete_query == 1 ]]; then
plus_targets=$(</tmp/mongo_autocomplete_plus_targets) plus_targets=$(</tmp/mongo_autocomplete_plus_targets)
query_output=$("${new_args[@]@Q}") query_output=$("${new_args[@]@Q}")
echo $query_output $plus_targets | tr " " "\n" echo $query_output $plus_targets | tr " " "\n" >&3
else else
$bazel_real "${new_args[@]}" trap - EXIT
bazel_exit_code=$? # Slow path: restore stdout/stderr so Bazel prints normally
# Run post-bazel hook in subshell exec 1>&3 2>&4
(>&2 $python $REPO_ROOT/bazel/wrapper_hook/post_bazel_hook.py $bazel_real)
exit $bazel_exit_code $bazel_real "${new_args[@]}"
fi bazel_exit_code=$?
( >&2 $python $REPO_ROOT/bazel/wrapper_hook/post_bazel_hook.py $bazel_real )
exit $bazel_exit_code
fi

View File

@ -1,6 +1,36 @@
@echo off @echo off
setlocal EnableDelayedExpansion setlocal EnableDelayedExpansion
rem Enable ANSI escape codes for colors (Windows 10+)
rem Get ESC character for ANSI colors (set once at the start)
for /f %%A in ('echo prompt $E ^| cmd') do set "ESC=%%A"
rem Enable virtual terminal processing for ANSI escape codes (Windows 10+)
rem Create a temporary PowerShell script to enable VT processing
set "VT_SCRIPT=%TEMP%\bazel_vt_%RANDOM%.ps1"
(
echo [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
echo $signature = @'
echo [DllImport("kernel32.dll", SetLastError=true^)]
echo public static extern IntPtr GetStdHandle(int nStdHandle^);
echo [DllImport("kernel32.dll", SetLastError=true^)]
echo public static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode^);
echo [DllImport("kernel32.dll", SetLastError=true^)]
echo public static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode^);
echo '@
echo $type = Add-Type -MemberDefinition $signature -Name Win32Utils -Namespace Console -PassThru
echo $STD_OUTPUT_HANDLE = -11
echo $STD_ERROR_HANDLE = -12
echo $ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
echo $hOut = $type::GetStdHandle($STD_OUTPUT_HANDLE^)
echo $hErr = $type::GetStdHandle($STD_ERROR_HANDLE^)
echo $mode = 0
echo if ($type::GetConsoleMode($hOut, [ref]$mode^)^) { $null = $type::SetConsoleMode($hOut, $mode -bor $ENABLE_VIRTUAL_TERMINAL_PROCESSING^) }
echo if ($type::GetConsoleMode($hErr, [ref]$mode^)^) { $null = $type::SetConsoleMode($hErr, $mode -bor $ENABLE_VIRTUAL_TERMINAL_PROCESSING^) }
) > "%VT_SCRIPT%"
>nul 2>&1 powershell -NoProfile -ExecutionPolicy Bypass -File "%VT_SCRIPT%"
del "%VT_SCRIPT%" >nul 2>&1
echo common --//bazel/config:running_through_bazelisk > .bazelrc.bazelisk echo common --//bazel/config:running_through_bazelisk > .bazelrc.bazelisk
set REPO_ROOT=%~dp0.. set REPO_ROOT=%~dp0..
@ -40,22 +70,51 @@ if !skip_python!=="0" if !current_bazel_command!=="info" set skip_python="1"
if !skip_python!=="1" ( if !skip_python!=="1" (
"%BAZEL_REAL%" %* "%BAZEL_REAL%" %*
exit %ERRORLEVEL% exit /b %ERRORLEVEL%
) )
rem === Set up logging for SLOW_PATH (equivalent to bash SLOW_PATH=1) ===
rem Where the log will be stored
set "LOG_DIR=%REPO_ROOT%\.bazel_logs"
if not exist "%LOG_DIR%" mkdir "%LOG_DIR%"
set "LOGFILE=%LOG_DIR%\bazel_wrapper_%DATE:/=_%_%TIME::=_%_%RANDOM%.log"
rem Set up environment variables for terminal output (for engflow_check.py)
rem On Windows, we use CON device for console output
rem Note: Windows doesn't support file descriptor duplication like Unix,
rem so we'll set these to indicate console output should go to CON
set "MONGO_WRAPPER_STDOUT_FD=CON"
set "MONGO_WRAPPER_STDERR_FD=CON"
rem === Start timing ===
set STARTTIME=%TIME%
rem === Capture output to logfile starting now ===
rem Note: We redirect Python installation and wrapper_hook.py output to logfile
REM find existing python installs REM find existing python installs
set python="" set python=""
if exist %REPO_ROOT%\bazel-%cur_dir% ( if exist %REPO_ROOT%\bazel-%cur_dir% (
call :find_pyhon call :find_pyhon
) )
if not exist "!python!" ( if not exist "!python!" (
echo python prereq missing, using bazel to install python... 1>&2 (
"%BAZEL_REAL%" build --bes_backend= --bes_results_url= @py_windows_x86_64//:all 1>&2 echo python prereq missing, using bazel to install python...
"%BAZEL_REAL%" build --bes_backend= --bes_results_url= @py_windows_x86_64//:all
if %ERRORLEVEL% NEQ 0 ( if !ERRORLEVEL! NEQ 0 (
if "%CI%"=="" if "%MONGO_BAZEL_WRAPPER_FALLBACK%"=="" exit %ERRORLEVEL% "%BAZEL_REAL%" build --config=local @py_windows_x86_64//:all
echo wrapper script failed to install python! falling back to normal bazel call... 1>&2 if !ERRORLEVEL! NEQ 0 (
"%BAZEL_REAL%" %* if "%CI%"=="" if "%MONGO_BAZEL_WRAPPER_FALLBACK%"=="" exit /b !ERRORLEVEL!
exit %ERRORLEVEL% echo wrapper script failed to install python! falling back to normal bazel call...
"%BAZEL_REAL%" %*
exit /b !ERRORLEVEL!
)
)
) > "%LOGFILE%" 2>&1
if !ERRORLEVEL! NEQ 0 (
echo %ESC%[1;31mERROR:%ESC%[0m Python installation failed:
type "%LOGFILE%"
exit /b !ERRORLEVEL!
) )
) )
@ -63,18 +122,55 @@ if not exist "!python!" (
call :find_pyhon call :find_pyhon
) )
SET STARTTIME=%TIME% rem === Call Python wrapper, log to file ===
set "MONGO_BAZEL_WRAPPER_ARGS=%tmp%\bat~%RANDOM%.tmp" set "MONGO_BAZEL_WRAPPER_ARGS=%tmp%\bat~%RANDOM%.tmp"
echo "" > %MONGO_BAZEL_WRAPPER_ARGS% echo "" > %MONGO_BAZEL_WRAPPER_ARGS%
%python% %REPO_ROOT%/bazel/wrapper_hook/wrapper_hook.py "%BAZEL_REAL%" %* 1>&2
if %ERRORLEVEL% NEQ 0 ( rem Print info message to terminal (equivalent to bash echo to FD 4)
if "%CI%"=="" if "%MONGO_BAZEL_WRAPPER_FALLBACK%"=="" exit %ERRORLEVEL% echo %ESC%[0;32mINFO:%ESC%[0m running wrapper hook... 1>&2
echo wrapper script failed! falling back to normal bazel call... 1>&2
"%BAZEL_REAL%" %* (
exit %ERRORLEVEL% %python% %REPO_ROOT%/bazel/wrapper_hook/wrapper_hook.py "%BAZEL_REAL%" %*
) >> "%LOGFILE%" 2>&1
set "exit_code=%ERRORLEVEL%"
rem Linter fails preempt bazel run (exit code 3)
if %exit_code% EQU 3 (
echo %ESC%[0;31mERROR:%ESC%[0m Linter run failed, see details above 1>&2
echo %ESC%[0;32mINFO:%ESC%[0m Run the following to try to auto-fix the errors: 1>&2
echo. 1>&2
echo bazel run lint --fix 1>&2
exit /b %exit_code%
) )
rem Calculate duration for summary (equivalent to bash print_summary)
set ENDTIME=%TIME%
FOR /F "tokens=1-4 delims=:.," %%a IN ("%STARTTIME%") DO (
SET /A "start=(((%%a*60)+1%%b %% 100)*60+1%%c %% 100)*100+1%%d %% 100"
)
FOR /F "tokens=1-4 delims=:.," %%a IN ("%ENDTIME%") DO (
SET /A "end=(((%%a*60)+1%%b %% 100)*60+1%%c %% 100)*100+1%%d %% 100"
)
SET /A elapsed=end-start
SET /A hh=elapsed/(60*60*100), rest=elapsed%%(60*60*100), mm=rest/(60*100), rest%%=60*100, ss=rest/100, cc=rest%%100
IF %hh% lss 10 SET hh=0%hh%
IF %mm% lss 10 SET mm=0%mm%
IF %ss% lss 10 SET ss=0%ss%
IF %cc% lss 10 SET cc=0%cc%
if %exit_code% NEQ 0 (
echo %ESC%[1;31mERROR:%ESC%[0m wrapper hook failed: 1>&2
type "%LOGFILE%" 1>&2
if "%CI%"=="" if "%MONGO_BAZEL_WRAPPER_FALLBACK%"=="" exit /b %exit_code%
echo wrapper script failed! falling back to normal bazel call... 1>&2
"%BAZEL_REAL%" %*
exit /b %ERRORLEVEL%
)
rem === Read new args back in ===
set "new_args="
for /F "delims=" %%a in (%MONGO_BAZEL_WRAPPER_ARGS%) do ( for /F "delims=" %%a in (%MONGO_BAZEL_WRAPPER_ARGS%) do (
set str="%%a" set str="%%a"
call set str=!str: =^ ! call set str=!str: =^ !
@ -82,43 +178,21 @@ for /F "delims=" %%a in (%MONGO_BAZEL_WRAPPER_ARGS%) do (
) )
del %MONGO_BAZEL_WRAPPER_ARGS% del %MONGO_BAZEL_WRAPPER_ARGS%
REM Final Calculations if "%MONGO_BAZEL_WRAPPER_DEBUG%"=="1" (
SET ENDTIME=%TIME% echo [WRAPPER_HOOK_DEBUG]: wrapper hook script input args: %* 1>&2
FOR /F "tokens=1-4 delims=:.," %%a IN ("%STARTTIME%") DO ( echo [WRAPPER_HOOK_DEBUG]: wrapper hook script new args: !new_args! 1>&2
SET /A "start=(((%%a*60)+1%%b %% 100)*60+1%%c %% 100)*100+1%%d %% 100" echo [WRAPPER_HOOK_DEBUG]: wrapper hook script took %mm%m and %ss%.%cc%s 1>&2
)
FOR /F "tokens=1-4 delims=:.," %%a IN ("%ENDTIME%") DO (
SET /A "end=(((%%a*60)+1%%b %% 100)*60+1%%c %% 100)*100+1%%d %% 100"
)
REM Calculate the elapsed time by subtracting values
SET /A elapsed=end-start
REM Format the results for output
SET /A hh=elapsed/(60*60*100), rest=elapsed%%(60*60*100), mm=rest/(60*100), rest%%=60*100, ss=rest/100, cc=rest%%100
IF %hh% lss 10 SET hh=0%hh%
IF %mm% lss 10 SET mm=0%mm%
IF %ss% lss 10 SET ss=0%ss%
IF %cc% lss 10 SET cc=0%cc%
SET DURATION=%mm%m and %ss%.%cc%s
if "%MONGO_BAZEL_WRAPPER_DEBUG%"=="1" (
ECHO [WRAPPER_HOOK_DEBUG]: wrapper hook script input args: %* 1>&2
ECHO [WRAPPER_HOOK_DEBUG]: wrapper hook script new args: !new_args! 1>&2
ECHO [WRAPPER_HOOK_DEBUG]: wrapper hook script took %DURATION% 1>&2
) )
"%BAZEL_REAL%" !new_args! "%BAZEL_REAL%" !new_args!
exit /b %ERRORLEVEL%
EXIT /B %ERRORLEVEL%
:: Functions :: Functions
:find_pyhon :find_pyhon
dir %REPO_ROOT% | C:\Windows\System32\find.exe "bazel-%cur_dir%" > %REPO_ROOT%\tmp_bazel_symlink_dir.txt dir %REPO_ROOT% | C:\Windows\System32\find.exe "bazel-%cur_dir%" > %REPO_ROOT%\tmp_bazel_symlink_dir.txt
for /f "tokens=2 delims=[" %%i in (%REPO_ROOT%\tmp_bazel_symlink_dir.txt) do set bazel_real_dir=%%i for /f "tokens=2 delims=[" %%i in (%REPO_ROOT%\tmp_bazel_symlink_dir.txt) do set bazel_real_dir=%%i
del %REPO_ROOT%\tmp_bazel_symlink_dir.txt del %REPO_ROOT%\tmp_bazel_symlink_dir.txt
set bazel_real_dir=!bazel_real_dir:~0,-1! set bazel_real_dir=!bazel_real_dir:~0,-1!
set python="!bazel_real_dir!\..\..\external\_main~setup_mongo_python_toolchains~py_windows_x86_64\dist\python.exe" set python="!bazel_real_dir!\..\..\external\_main~setup_mongo_python_toolchains~py_windows_x86_64\dist\python.exe"
EXIT /B 0 exit /b 0