A scripted SMS Trace
Summary: SMS Trace (trace32.exe) is the core tool in every SMS administrator's toolkit. But do you really have time to be watching logs fly by? Why not script what you need to watch for and thus let your console do the watching?
SMS Trace has always impressed me - what kind of wonderful developer magic makes it possible to display new lines as they're added to logs in real time? What is the mysterious API that makes that possible? As a scripter I always wanted to hook into trace32 so it would 'shout' when the event I wanted would happen (highlighting helps, but can quickly scroll away). Or translate lines as they go by (what does that GUID mean?). Or relate one log to another (what does the scheduler do after the distribution manager does its tasks?)
Well today things built up to the point where I could no longer ignore this possibility. I wasn't particularly optimistic that vbscript could work such magic, but I really can't afford to be manually chasing rare yet important scenarios. With a bit of research I found that SMS Trace isn't quite as magical as we might think.
It turns out that long ago in the UNIX world they developed a tool called Tail.exe to show the last lines. Then they added a "follow" function to show new lines as they were added to the file - sound familiar? Of course such tools are also available in the Windows world, and they're simple enough that the source code is often shared.
How do such tools work? Well it's actually pretty basic - check the file frequently (say every 1/4 second) to see if the file size has changed. If so, open it and jump to the point you last read. Read the rest of the file to the end-of-file. Display the results and repeat. Is that disappointing, or what? That's not magical. It sounds really inefficient (that's a lot of file opening for active logs), but it seems to work well, even in vbscript. I ran such code all day and it had no adverse effect on my console or server (I didn't monitor the network, but if SMS Trace does the same thing then we've been getting away with it for years).
I'll include the code in a moment, but first a bit of the envisioning thing: it won't take a lot of scripting skills to build the real solutions around this kind of code. For example, it's Patch Tuesday (or Patch Wednesday if you're outside of North America), and you build your patch packages and deploy them. What's next? You watch the packages to make sure they get out to all your DPs (and thus your clients). Generally that goes well, but can you afford to just assume that it will be fine? If you work for a small to medium organization with a fairly stable and predictable environment the answer should be Yes. For the rest of us, we monitor everything closely in real time - with SMS Trace. So what if one of us writes the script to do that watching and shares it? Everyone benefits! The same can be done for all the other common SMS activities. So I hope some of you will experiment with this idea and then start sharing.
Code time (fully working sample this time):
logfile = "replmgr.log" 'it changes a lot so it's a good example
Const ForReading = 1
Set fso = CreateObject("Scripting.FileSystemObject")
prev_size = fso.GetFile( logfile ).Size
while 1=1
file_found = false
while not file_found 'handle rollovers
on error resume next
current_size = fso.GetFile( logfile ).Size 'on file rollovers, when the file switches from .log to .lo_, this line could fail, momentarily
if err=0 then
on error goto 0
if current_size < prev_size then prev_size = 0 'it must have rolled over but not been caught when checking the size
file_found = true
else
on error goto 0
prev_size = 0 'to guarantee no data loss we should get the end of the previous version of the file first
try = try + 1
if try=10 then wscript.echo "couldn't find file to get its size" : wscript.quit
wscript.sleep 1000 'wait a second before looking for the next one
end if
wend
'display changes in the file
if current_size <> prev_size then
Set f = fso.OpenTextFile(logfile, ForReading)
f.skip( prev_size ) 'this can be slow on large files, especially at times of large changes to the file, but not bad (2 or 3 seconds at worst?)
new_data = f.read( current_size - prev_size ) 'there are other ways to do this, but this seems to work best
f.close
new_lines = split( new_data, vbCRLF )
for each new_line in new_lines
if new_line<>"" then wscript.echo new_line
next
end if
prev_size = current_size
wscript.sleep 250 'pause before checking again
wend
And what does the output look like? Just like SMS Trace. Run them side by side and you'll see the same output at the same time. Occasionally the script will hesitate, but even then only for a few seconds. Of course the real point is for you to add value by adding logic to only show the lines you want. Or in a more meaningful format. Or whatever.