vbScript - Create a Log File Using vbScript Classes

Reverend Jim 0 Tallied Votes 3K Views Share

vbScript - Create a Log File Using vbScript Classes

Before I retired I was responsible for most of the corporate data plumbing at our control centre. All of the plumbing was written in vbScript. As any maintenance programmer knows, log files are a vital key in identifying and fixing problems. Because I am basically lazy I don't like to code the same process over and over so I created logging code that could be included in any script. The scripts were run automatically on periods ranging from once every five minutes to once a week, or even as little as once a month. Depending on the activity, log files had the potential of becoming very large and unmanageable so I added the option of creating separate log files based on the day, month, or even year. To keep the names standardized I made the default log file name the same as the script that was creating it, except with a .log file extension as well as a custom tag based on the log type. Logs can be of type daily, monthly, yearly, or forever and the file names are modified as follows:

daily           <scriptname> YYYY-MM-DD.log
monthly         <scriptname> YYYY-MM.log
yearly          <scriptname> YYYY.log
forever         <scriptname>.log

Just as in the full vb.Net, in vbScript, you can define classes and instantiate them at run time. You won't have the full set of features you would find in vb.Net, but enough to be useful. A class in vbScript is defined as follows

Class classname
    .
    .
    .
End Class

Inside you define properties and methods, again, similar to vb.Net but with restrictions. For example, in vbScript there is no function overloading. Properties and methods can be declared Public (available outside the class) or Private (available only within the class). Properties can be read/write or read only. To declare a public property you do

Public varname

and you refer to that property as obj.varname as you would expect. Purists will say that you should never declare a public property. You should declare a private property then access it using Let/Set/Get interfaces. For example

Class myClass

    Private m_Name

    Public Property Let Name(val)
        m_Name = val
    End Property

    Public Property Get Name()
        Name = m_Name
    End Property

End Class

This give you a public property, Name that is read/write. To make it read only just remove the Let block. Set is the same as Let except that it is used for object properties. Lastly I want to discuss constructors and destructors. Any code you want to run when the object is created must go inside the sub

Private Sub Class_Initialize ()
    .
    .
    .
End Sub

and any cleanup that you want to do when the object is destroyed must go inside

Private Sub Class_Terminate()
    .
    .
    .
End Sub

Methods can also be public or private. You'll notice that my private property is prefixed with m_. This is simply a convention I follow to visually distinguish public properties and methods from private ones.

So much for the quickie tutorial. Let me just touch briefly on how to use the logger class.

You create an instance of the logger object by

Set logger = New clsLogger

and then, unless you want the default log type, you set the type either by

logger.LogType = "daily"

or

logger.Open("daily")

If you are expecting low logger activity you can use the former, and the log file will be opened and closed for each write. If you are expecting higher activity you can use the latter and manually close it when done, or let the destructor close the file. You write events to the log file by one of

logger.Write(text)
logger.Tee(dest,text)

The first writes text to the log file. The second writes it to either the log file (dest="F"), the console (dest="C") or both (dest="B"). The string text can contain vbCrLr characters, or more conveniently, \n which will be translated to vbCrLf. Every line is written, prefixed with the current date and time as YYYY-MM-DD HH:MM:SS. You can also write a separator line by

logger.Separator()

which writes a line of the form

2018-07-25 10:38:00 -------------------- D:\utils\vb.wsf RUNNING ON JIM-PC
''#region Header                                                                        '
''                                                                                      '
''  Name:                                                                               '
''                                                                                      '
''      Logger.vbs                                                                      '
''                                                                                      '
''  Description:                                                                        '
''                                                                                      '
''      This file defines the Logger class for maintaining log files.                   '
''                                                                                      '
''  Properties:                                                                         '
''                                                                                      '
''      LogFile                                                                         '
''                                                                                      '
''          The name of the log file.                                                   '
''          Default is scriptname.log (scriptname is the name of the running script)    '
''          including the full path name of the script. scriptname may be appended with '
''          date info based on LogType.                                                 '
''                                                                                      '
''          Assign your own log name before the first write to override the default.    '
''                                                                                      '
''      LogType (not case sensitive)                                                    '
''                                                                                      '
''          "d" or "daily"    - a new log file for each day                             '
''          "m" or "monthly"  - a new log file for each month                           '
''          "y" or "yearly"   - a new log file for each year                            '
''          ""                - one horking big log file (default)                      '
''                                                                                      '
''  Methods:                                                                            '
''                                                                                      '
''      Open(type)                                                                      '
''                                                                                      '
''          Opens the log file fr append (will create if it doesn't exist)              '
''          Type is one of "", "d", "m", "y" (see LogType property)                     '
''                                                                                      '
''      Close()                                                                         '
''                                                                                      '
''          Closes a log file if it is open                                             '
''                                                                                      '
''      Write(text)                                                                     '
''                                                                                      '
''          Writes the text to the log file prefixed with the current date and time     '
''          Text is the message you want to log. If the text contains multiple lines    '
''          ending in vbCrLf or \n then each line will be written prefixed with the     '
''          date and time.                                                              '
''                                                                                      '
''                                                                                      '
''      Tee(dest,text)                                                                  '
''                                                                                      '
''          Writes the text to either or both of the console window and the log file.   '
''          Text is the message you want to log.                                        '
''                                                                                      '
''          dest = "C" - write text to the console window only                          '
''          dest = "F" - write text to the log file only                                '
''          dest = "B" - write text to both the console window and the log file         '
''                                                                                      '
''  Notes:                                                                              '
''                                                                                      '
''      If you don't explicitly open and close the log file then it will be opened      '
''      before the message is written, then closed. For high volume or burst logging    '
''      it is better to manually open and close the log file.                           '
''                                                                                      '
''  Audit:                                                                              '
''                                                                                      '
''      2002-08-30  rj  original code                                                   '
''                                                                                      '
''#endregion                                                                            '

Class clsLogger

    Public  LogType      'the log file type (one of d m y or null)                      '
    Public  LogFile      'the log file name                                             '

    Private m_LogOpen    'true if the log file is currently open, false otherwise       '
    Private m_wso        'workplace shell object                                        '
    Private m_fso        'file system object                                            '
    Private m_tso        'text stream object                                            '
    Private m_so         'standard out stream                                           '
    
    Private m_script     'fully qualified name of the parent script                     '
    Private m_computer   'name of the computer on which the script is running           '

    'Initialize the class                                                               '

    Private Sub Class_Initialize ()

        Set m_wso  = CreateObject("Wscript.Shell")
        Set m_fso  = CreateObject("Scripting.FileSystemObject")

        m_LogOpen  = False
        m_script   = WScript.ScriptFullName
        m_computer = m_wso.ExpandEnvironmentStrings("%COMPUTERNAME%")
        set m_so   = WScript.StdOut

        LogFile    = ""
        LogType    = ""

    End Sub

    'Terminate the class                                                                 '

    Private Sub Class_Terminate()

        If m_LogOpen Then Close

        Set m_tso = Nothing
        Set m_fso = Nothing
        Set m_wso = Nothing

    End Sub

    'Open the log file                                                                  '
    '                                                                                   '
    '   thetype is one of (not case sensitive)                                          '
    '                                                                                   '
    '       d or daily      - log file named "<script> yyyy-mm-dd.log"                  '
    '       m or monthly    - log file named "<script> yyyy-mm.log"                     '
    '       y or yearly     - log file named "<script> yyyy.log"                        '
    '       null            - log file named "<script>.log"                             '
    
    Public Function Open (thetype)

        LogType = Lcase(Left(thetype,1))

        If LogFile = "" Then Call m_SetLogName

        If Not m_LogOpen Then
            Set m_tso = m_fso.OpenTextFile(LogFile,8,True)  '8 = Append, True = Create  '
            m_LogOpen = True
            Open      = True
        End If

    End Function

    ''Close the log file                                                                '
    
    Public Sub Close ()

        If m_LogOpen Then
            m_tso.Close()
            m_LogOpen = False
        End If

    End Sub

    ''Write a message to the log file                                                   '
    
    Public Sub Write (text)
        Tee "F", text
    End Sub

    ''Write a message to either or both the console window and the log file             '
    
    Public Sub Tee (dest,text)

        If m_LogOpen Then
            m_WriteLine dest,text
        Else
            Open LogType
            m_WriteLine dest,text
            Close
        End If

    End Sub

    ''Write a separator line in the log file                                            '
    
    Public Sub Separator()
        Tee "F", String(20,"-") & " " & m_script & " RUNNING ON " & m_computer
    End Sub

    ''Set a log file name based on the executing script name and the log type           '
    
    Private Sub m_SetLogName()

        LogFile = " " & Year(Date) & "-" & Right("0"&Month(Date),2) & "-" & Right("0"&Day(Date),2)

        Select Case Lcase(Left(LogType,1))
            Case "y" : LogFile = Left(LogFile, 5)   ' " YYYY"       '
            Case "m" : LogFile = Left(LogFile, 8)   ' " YYYY-MM"    '
            Case "d" : LogFile = Left(LogFile,11)   ' " YYYY-MM-DD" '
            Case Else: LogFile = ""                 ' ""            '
        End Select

        LogFile = m_fso.GetParentFolderName(m_script) & "\" & m_fso.GetBaseName(m_script) _
                & LogFile & ".log"

    End Sub

    ''Write one or more lines to the console window or the log file                     '
    ''                                                                                  '
    ''   dest = 1 or "C" - write to console                                             '
    ''   dest = 2 or "F" - write to file                                                '
    ''   dest = 3 or "B" - write to both                                                '
    
    Private Sub m_WriteLine (dest, ByVal text)

        Dim line
        Dim datestamp

        'create datestamp in the form "YYYY-MM-DD HH:MM:SS"

        datestamp = Year(Now)      & "-" & Pad(Month(Now))  & "-" & Pad(Day(Now)) & " " _
                  & Pad(Hour(Now)) & ":" & Pad(Minute(Now)) & ":" & Pad(Second(Now))

        'Replace inline \n with newlines

        text = Replace(text,"\n",VbCrLf)

        For Each line In Split(text,vbCrLf)

            Select Case Ucase(Left(dest,1))
                Case "C"
                    m_so.WriteLine (datestamp & " " & line)
                Case "F"
                    m_Tso.WriteLine datestamp & " " & line
                Case "B"
                    m_so.WriteLine (datestamp & " " & line)
                    m_Tso.WriteLine datestamp & " " & line
                Case Else
                    m_Tso.WriteLine datestamp & " " & line
            End Select

        Next

    End Sub

    ''Pad a number on the left with "0" to two places                                   '
    
    Private Function Pad(num)
        Pad = Right("00" & num,2)
    End Function

End Class