Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added parameters to ebpf_tracing.cmd, revised tracing/cleanup logic #2400

Merged
merged 14 commits into from
Apr 29, 2023
165 changes: 116 additions & 49 deletions scripts/ebpf_tracing.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -3,76 +3,131 @@

@rem Script behavior:
@rem - When called with 'start', it will:
@rem - Setup the logman session named as defined in 'trace_name', capping circular-log file size to 'max_size_mb', and generating every 'logman_period'.
@rem - Setup the logman session named as defined in 'trace_name', capping circular-log file size to 'max_file_size_mb', and generating every 'rundown_period'.
@rem - Configure the WFP/eBPF events to be monitored
@rem - Start the session within the given 'tracePath' directory.
@rem - Start the session within the given 'trace_path' directory.
@rem - When called with 'stop', it will:
@rem - Stop then delete the logman session, and finally deletes the 'tracePath' directory.
@rem - Stop then delete the logman session, and finally deletes the 'trace_path' directory.
@rem - When called with 'periodic', it will:
@rem - Run 'netsh wfp show state' into the 'tracePath' directory, and if the file is under 'max_size_mb', it will move it into the '.\committed' subfolder, adding a timestamp to its name.
@rem - Iterate over all the '.etl' files in the 'tracePath' directory, sorted in descending order by "date modified", skip the first 'num_etl_files_to_keep' files and move the others into the '.\committed' subfolder.
@rem - Run 'netsh wfp show state' into the 'trace_path' directory, and if the file is under 'max_file_size_mb', it will move it into the '.\committed' subfolder, adding a timestamp to its name.
@rem - Iterate over all the '.etl' files in the 'trace_path' directory, sorted in descending order by "date modified", skip the first 'num_etl_files_to_keep' files and move the others into the '.\committed' subfolder.
@rem - Iterate over all the '.etl' and '.xml' files in the '.\committed' subfolder and delete files older than 'files_max_age_days' days.

@echo off
setlocal enabledelayedexpansion

@rem Check the number of arguments and their validity.
if "%~1"=="" goto usage
if "%~2"=="" goto usage
set option=%1
set tracePath=%~2
if not exist "!tracePath!" (
mkdir "!tracePath!"
@rem Define the default parameters values for the tracing session and the periodic cleanup job.
set "command="
set "trace_path="
set "trace_name=ebpf_diag"
set "rundown_period=0:35:00"
set "max_file_size_mb=20"
set "max_committed_etl_files=30"
set "max_committed_wfp_state_files=1"

:parse_args
if "%~1" == "" goto :validate_args
if /i "%~1" == "start" set "command=%~1" & shift & goto :parse_args
if /i "%~1" == "stop" set "command=%~1" & shift & goto :parse_args
if /i "%~1" == "periodic" set "command=%~1" & shift & goto :parse_args
if "%~1" == "/trace_path" set "trace_path=%~2" & shift & shift & goto :parse_args
if "%~1" == "/trace_name" set "trace_name=%~2" & shift & shift & goto :parse_args
if "%~1" == "/rundown_period" set rundown_period=%~2 & shift & shift & goto :parse_args
if "%~1" == "/max_file_size_mb" set max_file_size_mb=%~2 & shift & shift & goto :parse_args
if "%~1" == "/max_committed_etl_files" set max_committed_etl_files=%~2 & shift & shift & goto :parse_args
if "%~1" == "/max_committed_wfp_state_files" set max_committed_wfp_state_files=%~2 & shift & shift & goto :parse_args
echo Unknown parameter: "%~1"
goto :usage

:validate_args
if "%command%" == "" (
echo Mandatory parameter 'command' is missing.
goto :usage
)
if not "%command%" == "start" if not "%command%" == "stop" if not "%command%" == "periodic" (
echo Error: Invalid command specified: '%command%'. Valid values are start, stop, and periodic.
goto :usage
)
if "%trace_path%" == "" (
echo Error: Mandatory parameter 'trace_path' is missing.
goto :usage
)

@rem Define the parameters for the tracing session and the periodic cleanup job.
set trace_name="ebpf_diag"
set logman_period=0:35:00
set /a max_size_mb=20
set /a max_size_bytes=max_size_mb*1000000
set /a files_max_age_days=1
:run_command
@rem Uncomment ECHOs below for debugging purposes.
@rem ----------------------------------------------
@rem echo Running with the following parameter values:
@rem echo command=%command%
@rem echo trace_path=%trace_path%
@rem echo trace_name=%trace_name%
@rem echo rundown_period=%rundown_period%
@rem echo max_file_size_mb=%max_file_size_mb%
@rem echo max_committed_etl_files=%max_committed_etl_files%
@rem echo max_committed_wfp_state_files=%max_committed_wfp_state_files%
matthewige marked this conversation as resolved.
Show resolved Hide resolved

@rem Internal constants
set /a num_etl_files_to_keep=1
set /a max_file_size_bytes=!max_file_size_mb!*1000000

if not exist "!trace_path!" (
echo Creating trace_path "!trace_path!"
mkdir "!trace_path!"
)

if "%option%"=="periodic" (
if "%command%"=="periodic" (

@rem Create a subdirectory for the committed files (if not already present).
set "traceCommittedPath=!tracePath!\committed"
set "traceCommittedPath=!trace_path!\committed"
if not exist "!traceCommittedPath!" (
mkdir "!traceCommittedPath!"
)

@rem Run down the WFP state.
pushd "!tracePath!"
pushd "!trace_path!"
netsh wfp show state
popd
set "wfp_state_file=!tracePath!\wfpstate.xml"
if exist "!wfp_state_file!" (
@rem If the file size is less or equal than 'max_size_mb', then move it to the 'traceCommittedPath' directory (otherwise it'll just be overwritten by the next run down).
for /f "tokens=2 delims==" %%a in ('wmic OS Get localdatetime /value') do set "dt=%%a"
set "YYYY=!dt:~0,4!" & set "MM=!dt:~4,2!" & set "DD=!dt:~6,2!"
set "HH=!dt:~8,2!" & set "Min=!dt:~10,2!" & set "Sec=!dt:~12,2!"
set "timestamp=!YYYY!!MM!!DD!_!HH!!Min!!Sec!"
for %%F in ("!wfp_state_file!") do (
if %%~zF LEQ %max_size_bytes% (
move /y "!wfp_state_file!" "!traceCommittedPath!\wfpstate_!timestamp!.xml" >nul
set "wfp_state_file_cab=!trace_path!\wfpstate.cab"
makecab "!trace_path!\wfpstate.xml" "!wfp_state_file_cab!"
if exist "!wfp_state_file_cab!" (

@rem If the file size is less or equal than 'max_file_size_mb', then move it to the 'traceCommittedPath' directory.
for %%F in ("!wfp_state_file_cab!") do (
if %%~zF LEQ %max_file_size_bytes% (

@rem Get the current date and time in a format suitable for file names.
for /f "tokens=2 delims==" %%a in ('wmic OS Get localdatetime /value') do (
set "dt=%%a"
set "YYYY=!dt:~0,4!" & set "MM=!dt:~4,2!" & set "DD=!dt:~6,2!"
set "HH=!dt:~8,2!" & set "Min=!dt:~10,2!" & set "Sec=!dt:~12,2!"
set "timestamp=!YYYY!!MM!!DD!_!HH!!Min!!Sec!"

@rem Move the .CAB file to the 'traceCommittedPath' directory.
move /y "!wfp_state_file_cab!" "!traceCommittedPath!\wfpstate_!timestamp!.cab" >nul
)
) else (

@rem If the .CAB file size is greater than 'max_file_size_mb', then delete it.
del "!wfp_state_file_cab!"
)
)
)

@rem Iterate over all the .etl files in the 'tracePath' directory, sorted in descending order by "date modified",
@rem Iterate over all the .etl files in the 'trace_path' directory, sorted in descending order by name,
@rem and skip the first 'num_etl_files_to_keep' files (i.e., the newest 'num_etl_files_to_keep' files).
for /f "skip=%num_etl_files_to_keep% delims=" %%f in ('dir /b /o-n "!tracePath!\*.etl"') do (
move /y "!tracePath!\%%f" "!traceCommittedPath!" >nul
for /f "skip=%num_etl_files_to_keep% delims=" %%f in ('dir /b /o-n "!trace_path!\*.etl"') do (
move /y "!trace_path!\%%f" "!traceCommittedPath!" >nul
)

@rem Iterate over all the .etl/.xml files in the 'traceCommittedPath' directory, and delete files older than 'files_max_age_days' days.
forfiles /p "!traceCommittedPath!" /s /m *.etl /d -%files_max_age_days% /c "cmd /c del @path" >nul
forfiles /p "!traceCommittedPath!" /s /m *.xml /d -%files_max_age_days% /c "cmd /c del @path" >nul
@rem Iterate over all the .ETL files in the 'traceCommittedPath' directory, and delete files overflowing `max_committed_etl_files`.
for /f "skip=%max_committed_etl_files% delims=" %%f in ('dir /b /o-d "!traceCommittedPath!\*.etl"') do ( del "!traceCommittedPath!\%%f" )

@rem Iterate over all the WFP-state files in the 'traceCommittedPath' directory, and delete files overflowing `max_committed_wfp_state_files`.
for /f "skip=%max_committed_wfp_state_files% delims=" %%f in ('dir /b /o-d "!traceCommittedPath!\wfpstate*.cab"') do ( del "!traceCommittedPath!\%%f" )

) else if "%option%"=="start" (
) else if "%command%"=="start" (

@rem Set up the tracing session.
logman create trace !trace_name! -o "!tracePath!\ebpf_trace" -f bincirc -max %max_size_mb% -cnf %logman_period% -v mmddhhmm
logman create trace !trace_name! -o "!trace_path!\ebpf_trace" -f bincirc -max %max_file_size_mb% -cnf %rundown_period% -v mmddhhmm

@rem Define the WFP events to be traced.
logman update trace !trace_name! -p "{00e7ee66-5b24-5c41-22cb-af98f63e2f90}" 0x7 0x4
Expand All @@ -84,22 +139,34 @@ if "%option%"=="periodic" (
@rem Start the tracing session.
logman start !trace_name!

) else if "%option%"=="stop" (
) else if "%command%"=="stop" (

@rem Stop and delete the tracing session.
logman stop !trace_name!
logman delete !trace_name!
rmdir /s /q "!tracePath!"

@rem Delete the tracing directory.
rmdir /s /q "!trace_path!"

) else (

goto usage
goto :usage
)
goto done
endlocal
exit /b 0

:usage
echo Usage: ebpf_tracing.cmd ^<start, stop, periodic^> ^<tracePath^>
echo Examples:
echo ebpf_tracing.cmd start "C:\_ebpf\logs"
echo ebpf_tracing.cmd stop "C:\_ebpf\logs"
echo ebpf_tracing.cmd periodic "C:\_ebpf\logs"
:done
echo Usage: ebpf_tracing.cmd command /trace_path path [/trace_name name] [/rundown_period ^<period as (H:mm:ss)^>] [/max_file_size_mb size] [/max_committed_etl_files count] [/max_committed_wfp_state_files count]
echo command (mandatory) Valid values are: [start, stop, periodic]
echo /trace_path path (mandatory) Path into which the tracing will be located (creates it if it does not exist).
echo /trace_name name Name of the logman trace (Default: "ebpf_diag")
echo /rundown_period period Period, expressed as (H:mm:ss) for saving and generating a new ETL log, and for generating a WFP state snapshot (Default: 0:35:00).
echo /max_file_size_mb size Maximum size set for an ETL log (Default: 20).
echo /max_committed_etl_files count Number of (most recent) .ETL files to keep in the main 'trace_path\committed' (Default: 30)
echo /max_committed_wfp_state_files count Number of (most recent) WFP-state .CAB files to keep in the main 'trace_path\committed' (Default: 1).
echo Examples (overriding defaults):
echo ebpf_tracing.cmd start /trace_name ebpf_diag /trace_path "%SystemRoot%\Logs\eBPF" /rundown_period 0:35:00 /max_file_size_mb 20
echo ebpf_tracing.cmd stop /trace_name ebpf_diag /trace_path "%SystemRoot%\Logs\eBPF"
echo ebpf_tracing.cmd periodic /trace_path "%SystemRoot%\Logs\eBPF" /max_file_size_mb 20 /max_committed_etl_files 30 /max_committed_wfp_state_files 1
endlocal
exit /b 1
Binary file modified scripts/ebpf_tracing_periodic_task.xml
Binary file not shown.
Binary file modified scripts/ebpf_tracing_startup_task.xml
Binary file not shown.