A Rolling File Appender in VBScript
I use log4j and log4net in most of my projects but I did not have a decent alternative for VBScript so I implemented my own. The script below implements the most important features of the log4j/log4net rolling file appender. It lets you configure:
- file to log to
- size of each file
- number of backups/old copies to keep
The code below uses test.txt as the log file with 4 backups. Test.txt contains the last logged data. When it is full, it is renamed to the backup file test.txt.1. The older logs are kept in the files test.txt.2, test.txt.3, … test.txt.N
Note that the size calculation is not accurate as the file is kept open. It is slower, but the size will be correct, if you open and close the file each time you log something. I did not care about accuracy so I chose the faster implementation below.
option explicit
'== CONFIG
const LOG_FILE = "C:\temp\test.txt"
const LOG_FILE_BACKUPS = 4
const LOG_FILE_SIZE_KB = 1000
const LOG_TO_CONSOLE = false
const LOG_FATAL = 0
const LOG_ERROR = 1
const LOG_WARN = 2
const LOG_INFO = 3
const LOG_DEBUG = 4
const LOG_FILE_LEVEL = 4
dim currentLogStream
set currentLogStream = nothing
'==== Test ONLY. Delete this section in production code
'Main tester
WScript.echo "Press CTRL+C to exit"
do while true
traceLog LOG_DEBUG, "Debug level test " & String(1000,"d")
traceLog LOG_INFO, "Info level test" & String(1000,"i")
traceLog LOG_WARN, "Warn level test" & String(1000,"w")
traceLog LOG_ERROR, "Error level test" & String(1000,"e")
traceLog LOG_FATAL, "Fatal level test" & String(1000,"f")
Wscript.sleep (1)
Loop
'==== End Test
public sub traceLog (level, message)
dim prefix
prefix = "[UNKNOWN]"
if level <= LOG_FILE_LEVEL then
select case level
case LOG_FATAL
prefix = "[FATAL]"
case LOG_ERROR
prefix = "[ERROR]"
case LOG_WARN
prefix = "[WARN]"
case LOG_INFO
prefix = "[INFO]"
case LOG_DEBUG
prefix = "[DEBUG]"
end select
rollingAppend prefix & vbTab & now() & vbTab & message
end if
end sub
sub rollingAppend (message)
'Special case the first time (file not opened)
dim oFS
dim oFile
dim fileNum
on error resume next 'NEVER bomb while logging
set oFS = CreateObject("Scripting.FileSystemObject")
if currentLogStream is nothing then
'Open stream for APPEND, creating the file if it does not exist
set currentLogStream = oFS.OpenTextFile(LOG_FILE, 8, true)
end if
'Log
currentLogStream.WriteLine (message)
if LOG_TO_CONSOLE then WScript.echo message
'Roll over if we should
set oFile = oFS.getFile(LOG_FILE)
if oFile.size >= LOG_FILE_SIZE_KB * 1024 then
currentLogStream.close()
set currentLogStream = nothing
'Delete the last backup
if oFS.FileExists(LOG_FILE & "." & LOG_FILE_BACKUPS) then
oFS.DeleteFile LOG_FILE & "." & LOG_FILE_BACKUPS
end if
'Rename all the old log files so log_file.1 -> 2, 2->3, etc.
for fileNum = LOG_FILE_BACKUPS - 1 to 1 step - 1
if oFS.FileExists (LOG_FILE & "." & fileNum) then
oFS.MoveFile LOG_FILE & "." & fileNum, LOG_FILE & "." & fileNum + 1
end if
next
'Move current file to .1
oFS.MoveFile LOG_FILE, LOG_FILE & "." & 1
end if
end sub