Creating a Log File Scanner
The Log File Scanner
Listing 12.6 shows the complete log file scanner.
Listing 12.6. ScanLog.vbs. Scans for "500" errors in an IIS log file.
' Scan a log file from a webserver for
' occurrences of " - 500" which indicates an
' internal server error
' get the log file
Dim varLogFile
varLogFile = InputBox ("Enter the complete " & _
"path and filename " & _
"of log file to scan.")
' create filesystemobject
Dim oFSO
Set oFSO = WScript.CreateObject("Scripting.FileSystemObject")
' open file into a TextStream object
Dim oTS
Set oTS = oFSO.OpenTextFile (varLogFile)
Dim oTSOut
Set oTSOut = oFSO.CreateTextFile ("c:\errors.htm")
' begin reading each line in the textstream
dim varLine, varFoundNone
varFoundNone = true
Do Until oTS.AtEndOfStream
varLine = oTS.ReadLine
' contains a 500 error?
If instr(1, varLine, " - 500 ") <> 0 Then
WScript.Echo varLine
oTSOut.WriteLine "<b>" & varline & "</b>"
varFoundNone = False
End If
Loop
' close the textstream
oTS.Close
oTSOut.Close
' found any?
If varFoundNone = True Then
WScript.Echo "Didn't find any errors."
Else
WScript.Echo "Found Error. You need to fix them."
End If
Before you can start using this script, you simply need to figure out where IIS stores its log files. Normally, it's in %systemroot%\LogFiles with a subfolder (such as W3Svc) for each virtual Web server that you've created.
The Log File Scanner-Explained
The script starts simply enough, by using an input box to ask for the complete path and filename of the log file to scan. This actually is a limitation of the script in its current form; in the next section, I'll enhance it to scan through every log file in a given folder, further automating the error-checking process.
' Scan a log file from a webserver for
' occurrences of " - 500" which indicates an
' internal server error
' get the log file
Dim varLogFile
varLogFile = InputBox ("Enter the complete path and filename " & _
"of log file to scan.")
Next, the script creates an FSO to work with.
' create filesystemobject
Dim oFSO
Set oFSO = WScript.CreateObject("Scripting.FileSystemObject")
Because the script has to read a text file, it needs to create a TextStream object. As you've already seen, the way to do this is to simply declare a variable, and then use one of the FSO methods that returns a TextStream. In this case, because the script just needs to read an existing file, it's using the OpenTextFile method.
' open file into a TextStream object
Dim oTS
Set oTS = oFSO.OpenTextFile (varLogFile)
The script is going to need to log any errors it finds, so it creates a second TextStream object. This one represents a new file, and the TextStream is obtained from the FSO's CreateTextFile method.
Dim oTSOut
Set oTSOut = oFSO.CreateTextFile ("c:\errors.htm")
Now the script needs to loop through the contents of the log file, which is opened for reading. I've created a variable, varFoundNone, and set it to the Boolean value of False. I'm using that variable to figure out if I've found any errors so that I can give an appropriate message at the end of the script. To loop through the log file, the script utilizes the AtEndOfStream property of the TextStream object. This property is automatically set to True when the script reaches the end of the file.
' begin reading each line in the textstream
dim varLine, varFoundNone
varFoundNone = true
Do Until oTS.AtEndOfStream
Next, the script reads a line of text from the file. The ReadLine method actually pulls an entire string of text and stores it in varLine. At the same time, ReadLine moves a pointer in the file to the next line, which is where the next ReadLine operation begins. This internal pointer is used to set the AtEndOfStream property to True when the end of the file is reached.
After reading the line of text, the script needs to see if it contains an ASP application error. Remember, each line of an IIS log file represents one logged message. If that line contains " - 500", it's an application error. To check, the script uses the InStr() function, telling the function to start looking for " - 500" at the first character of the line. InStr()returns a number indicating the character position where " - 500" was found. I don't really care about that; what's important is that InStr()returns a zero if it doesn't find " - 500" within the string.
varLine = oTS.ReadLine
' contains a 500 error?
If instr(1, varLine, " - 500 ") <> 0 Then
If there's no error in the line, the script skips down to the Loop and goes back to read the next line from the file. However, if InStr() finds the string, the script outputs the line of text using the WScript.Echo command. It also writes the line of text to the output file, prefixing it with <b> and suffixing it with </b> which are the HTML tags for boldfacing.
WScript.Echo varLine
oTSOut.WriteLine "<b>" & varline & "</b>"
varFoundNone = False
End If
Loop
Also notice that my tracking variable gets set to False when an error is found. At the end of the script, this lets me know that I did, in fact, find an error.
NOTE
The WScript.Echo command behaves differently depending on how you run the script. If you used WScript.exe (or just double-clicked on the VBS file, which does the same thing), the script displays a message box for each error line found in the log file. However, if you use Cscript.exe to execute the script from a command line, the errors will be written as command-line messages, and you won't be prompted to click OK for each one.
After the script reaches the end of the file, it can start wrapping up. The first step is to close both of the TextStreams that are open.
' close the textstream
oTS.Close
oTSOut.Close
Finally, the script needs to display an appropriate ending message. This is especially important because otherwise there's no clear indication that the script finished running, especially if no errors were found.
' found any?
If varFoundNone = True Then
WScript.Echo "Didn't find any errors."
Else
WScript.Echo "Found Error. You need to fix them."
End If
TIP
Why did I choose to add the HTML tags in the output file? Just for fun, mainly. In theory, I could have written the file to a Web server, allowing my company's Web application developers to easily access the file to review their application's errors. You can omit the <b> and </b> tags, and just e-mail the completed text file.
As I've already mentioned, the script is lacking in one significant way, which I'll fix in the next section.
The Enhanced Log File Scanner
As you know, IIS stores multiple log files in its log file folder. The odds that you're going to find the time to scan each new log file every day are slim, so it'd be nice if this script just asked for a folder and then scanned automatically through each log file it found there. Listing 12.7 does exactly that. The changes from the original log file scanner are shown in boldface.
Listing 12.7. ScanLog2.vbs. Scans for "500" errors in an IIS log file.
' Scan a log file from a webserver for
' occurrences of " - 500" which indicates an
' internal server error
' get the log file
Dim varLogPath
varLogPath = InputBox ("Enter the " & _
"complete path and logs folder.")
' create filesystemobject
Dim oFSO
Set oFSO = WScript.CreateObject("Scripting.FileSystemObject")
Dim oTSOut
Set oTSOut = oFSO.CreateTextFile ("c:\errors.htm")
' Loop through each file in the folder
Dim oFile, varFoundNone
varFoundNone = true
For Each oFile In oFSO.GetFolder("varLogPath").Files
'Is this a log file?
If Lcase(Right(oFile.Name,3)) = "log" Then
'Open the log file
Dim oTS
oTS = oFSO.OpenTextFile(oFSO.BuildPath(oFile.Path, _
oFile.Name))
' begin reading each line in the textstream
dim varLine
Do Until oTS.AtEndOfStream
varLine = oTS.ReadLine
' contains a 500 error?
If instr(1, varLine, " - 500 ") <> 0 Then
WScript.Echo varLine
oTSOut.WriteLine "<b>" & varline & "</b>"
varFoundNone = False
End If
Loop
' close the input textstream
oTS.Close
End If
Next
' close the output textstream
oTSOut.Close
' found any?
If varFoundNone = True Then
WScript.Echo "Didn't find any errors."
Else
WScript.Echo "Found Error. You need to fix them."
End If
This new script will run as-is on just about any system, provided you've given it the path to a folder that contains log files.
The Enhanced Log File Scanner-Explained
This enhanced script starts much like the previous one, but asks only for a folder name. The beauty of the way the FSO treats folder names is that it doesn't matter whether the user includes a trailing backslash; the script works fine either way.
' Scan a log file from a webserver for
' occurrences of " - 500" which indicates an
' internal server error
' get the log file
Dim varLogPath
varLogPath = InputBox ("Enter the complete path and logs folder.")
Another minor change is that only the output TextStream is opened at this point. Because the script is working with multiple files, it needs to open each one, one at a time, as it encounters them.
' create filesystemobject
Dim oFSO
Set oFSO = WScript.CreateObject("Scripting.FileSystemObject")
Dim oTSOut
Set oTSOut = oFSO.CreateTextFile ("c:\errors.htm")
Finally, the first big change. I've declared a variable to represent a file object, and I'm using a For Each…Next construct to loop through a collection of objects. Here's how it works: The FSO's GetFolder method returns a Folder object; specifically, it's returning the folder specified by the user from the earlier InputBox() function. The Folder object has a property called Files, which is a collection of File objects. The construct loops through each file in the collection. Each time through the loop, variable oFile will be set to a different file.
' Loop through each file in the folder
Dim oFile, varFoundNone
varFoundNone = true
For Each oFile In oFSO.GetFolder("varLogPath").Files
I cannot be assured that every file in the specified folder will be a log file, so I've used an If…Then construct. If the rightmost three characters of the filename are "log", I'll allow the script to work with the file and scan for errors. Otherwise, I'll skip the file. Notice the use of the Lcase() function to force the filename into lowercase characters. This ensures that files with a log or LOG filename extension will be scanned.
'Is this a log file?
If Lcase(Right(oFile.Name,3)) = "log" Then
Now I'm ready to open the log file-the current one, that is-into a TextStream. I'm still using the OpenTextFile method, along with the Path property of the File object. The Path property provides a complete path, including the filename, for the file.
'Open the log file
Dim oTS
oTS = oFSO.OpenTextFile(oFile.Path)
Most of the rest of the script is the same: Read each line of the file, scan for the error text, and output a message if an error is found.
dim varLine
' begin reading each line in the textstream
Do Until oTS.AtEndOfStream
varLine = oTS.ReadLine
' contains a 500 error?
If instr(1, varLine, " - 500 ") <> 0 Then
WScript.Echo varLine
oTSOut.WriteLine "<b>" & varline & "</b>"
varFoundNone = False
End If
Loop
Notice that I've had to rearrange the file closing statements. In this case, I'm finished reading the current input file, so I can close it before looping back up-via the Next statement-to open the next file in the folder.
' close the input textstream
oTS.Close
End If
Next
Finally, I can close the output text file and finish up as I did before.
' close the output textstream
oTSOut.Close
' found any?
If varFoundNone = True Then
WScript.Echo "Didn't find any errors."
Else
WScript.Echo "Found Error. You need to fix them."
End If
The new script is a much more efficient administrative tool, because it can be run whenever you like and always scans through every log file you have.
TIP
You could enhance this script to scan for other types of errors, such as the common errors that occur when a user tries to access a file that doesn't exist, or when users try to access a file that they're not authorized for.
|