How to Log Script Output to a File with Timestamps in Batch Script
Creating a record of what a script did and when it did it is crucial for debugging, auditing, and monitoring automated tasks. A simple log file can tell you if a process ran, what errors it encountered, and how long it took. The key to a useful log is the timestamp, which provides the chronological context for every event.
This guide will show you how to create a timestamped log file by combining the built-in %DATE% and %TIME% variables with output redirection. You will learn how to create a reusable logging function to ensure all your log entries are consistent, and how to capture the output of other commands in your log.
The Core Method: Appending Output with Timestamps
The basic technique involves three components:
ECHO: The command to generate the text you want to log.%DATE% %TIME%: The built-in variables that provide the current date and time.>>: The append redirection operator, which adds the output to the end of a file without overwriting it.
By combining these, you can create a simple, timestamped log entry.
Basic Example: Creating a Timestamped Log Entry
This script demonstrates the fundamental concept by writing two log entries to a file.
@ECHO OFF
SET "LOG_FILE=script_activity.log"
ECHO %DATE% %TIME% - Script execution started. >> "%LOG_FILE%"
REM Simulate some work
TIMEOUT /T 2 /NOBREAK > NUL
ECHO %DATE% %TIME% - Script execution finished. >> "%LOG_FILE%"
The resulting script_activity.log has each line prepended with the date and time of its execution.
Fri 10/27/2023 15:30:12.45 - Script execution started.
Fri 10/27/2023 15:30:14.47 - Script execution finished.
The format of %DATE% and %TIME% depends on your system's regional settings.
A Better Method: Creating a Reusable Log Function
Typing out the ECHO %DATE% %TIME% ... >> %LOG_FILE% command every time is repetitive and prone to error. A much cleaner approach is to create a subroutine (a function) that handles the formatting and redirection for you.
The following is the script with a :Log function:
@ECHO OFF
SET "LOG_FILE=script_activity.log"
CALL :Log "Script execution started."
CALL :Log "Processing user data..."
REM (Do some work here)
CALL :Log "Script execution finished."
GOTO :EOF
:Log
REM This subroutine takes one argument (the message) and logs it.
ECHO %DATE% %TIME% - %~1 >> "%LOG_FILE%"
GOTO :EOF
This is a far more maintainable and readable way to write your scripts. You simply CALL :Log with your message, and the subroutine handles the rest.
Logging the Output of Other Commands
Sometimes you need to log a message; other times you need to log the entire output of another command. You can redirect the output of any command to your log file.
This script runs the PING command and captures its full output in the log, framed by timestamped messages from our :Log function.
@ECHO OFF
SET "LOG_FILE=network_check.log"
CALL :Log "Starting network check..."
ECHO. >> "%LOG_FILE%"
REM Redirect the PING command's output directly to the log file.
PING google.com >> "%LOG_FILE%"
ECHO. >> "%LOG_FILE%"
CALL :Log "Network check finished."
GOTO :EOF
:Log
ECHO %DATE% %TIME% - %~1 >> "%LOG_FILE%"
GOTO :EOF
The resulting network_check.log:
Fri 10/27/2023 15:45:01.12 - Starting network check...
Pinging google.com [142.250.191.174] with 32 bytes of data:
Reply from 142.250.191.174: bytes=32 time=15ms TTL=118
Reply from 142.250.191.174: bytes=32 time=14ms TTL=118
Fri 10/27/2023 15:45:03.25 - Network check finished.
Common Pitfalls and How to Solve Them
Problem: Log File Path Contains Spaces
If your log file path has spaces (e.g., C:\My Scripts\logs\activity.log), failing to quote it will break the redirection.
Solution: Always Quote Your Log File Variable
This is a fundamental best practice. By enclosing the variable in double quotes, you ensure the command works regardless of the path.
REM This is the safe, correct way.
ECHO %DATE% %TIME% - My Message >> "%LOG_FILE%"
Problem: Colons in %TIME% Are Invalid for Filenames
You might want to create a unique log file for each run, using the date and time in the filename itself. However, the colons (:) in the %TIME% variable are not allowed in Windows filenames.
Solution: Use String Replacement
You can use string substitution to remove the colons before creating the filename.
@ECHO OFF
REM Replace colon characters with nothing
SET "SAFE_TIME=%TIME::=%"
REM Replace period/comma in fractional seconds (locale dependent)
SET "SAFE_TIME=%SAFE_TIME:.=%"
SET "SAFE_TIME=%SAFE_TIME:,=%"
SET "LOG_FILE=C:\Logs\activity_%DATE:~10,4%-%DATE:~4,2%-%DATE:~7,2%_%SAFE_TIME%.log"
ECHO This log file has a unique name: %LOG_FILE%
CALL :Log "This is the first entry in a unique log file."
GOTO :EOF
:Log
ECHO %DATE% %TIME% - %~1 >> "%LOG_FILE%"
GOTO :EOF
This creates a safe filename like activity_2023-10-27_15503012.log.
Practical Example: A Full Script with a Dedicated Log Function
This script performs a backup, logging each step with a reusable function and capturing command output where necessary.
@ECHO OFF
SETLOCAL
REM --- Configuration ---
SET "SOURCE_DIR=C:\Users\Admin\Documents"
SET "DEST_DIR=E:\Backups"
SET "LOG_FILE=E:\Backups\backup_log.txt"
REM --- Main Script Logic ---
CALL :Log "=============================="
CALL :Log "Backup script started."
IF NOT EXIST "%SOURCE_DIR%" (
CALL :Log "[ERROR] Source directory not found: %SOURCE_DIR%"
GOTO :End
)
CALL :Log "Starting Robocopy..."
ECHO. >> "%LOG_FILE%"
robocopy "%SOURCE_DIR%" "%DEST_DIR%" /MIR >> "%LOG_FILE%" 2>>&1
ECHO. >> "%LOG_FILE%"
CALL :Log "Robocopy finished."
:End
CALL :Log "Backup script finished."
GOTO :EOF
REM --- Logging Subroutine ---
:Log
REM Appends a timestamped message to the configured log file.
ECHO %DATE% %TIME% - %~1 >> "%LOG_FILE%"
GOTO :EOF
2>>&1 is used to redirect both standard output and error output from robocopy into the log file.
Conclusion
Logging is an essential part of writing serious, maintainable batch scripts. By adding timestamps, you transform a simple output file into a valuable diagnostic and auditing tool.
Key practices for effective logging:
- Combine
%DATE%,%TIME%, and the append operator>>to create timestamped entries. - Create a reusable
:Logsubroutine to keep your logging consistent and your main script logic clean. - Quote your log file paths (
"%LOG_FILE%") to prevent errors with spaces. - Redirect the output of external commands directly into the log when you need to capture their detailed results.