Eric,
Here's a complete logfile class written in VB 2005.
Option Explicit On
Option Compare Text
Option Strict On
Module LogInstance
Public logs as New LogFile
End Module
Public Class LogFile
Implements IDisposable
Private BaseFile As String = "" ' Contains all but the log file date and
extension
Private FileName As String = "" ' Contains the actual file that is being
written
Private Opened As Date ' When did this log file open
Private Const LogFileEntryDTStamp As String = "yyyyMMdd HH.mm.ss.fff"
Private Const LogFileNameDateStamp As String = "yyyyMMdd"
Private ts As StreamWriter ' Internal file control
' Protect multiple threads performing simultaneous writes to this log
file
Private LockWriteMessage As New System.Threading.SynchronizationContext
Public UseVersion As Boolean = True ' Controls version portion of file
name
Public Sub New()
End Sub
Public Sub New(ByVal fName As String)
Me.new()
Name = fName
End Sub
Public Property Name() As String
Get
Return FileName
End Get
Set(ByVal FileBase As String)
' Parse the FileBase into the path and base part of the
filename. Usually, FileBase will be the application name
If InStr(FileBase, "\") = 0 Then
BaseFile = Environ$("LogDir") ' In our
corporate environment, the Domain defines this via Group Policy
If BaseFile = "" Then BaseFile = "c:"
BaseFile = TrailSlash(BaseFile) & My.Application.Info.Title
Else
BaseFile = Left$(FileBase, InStrRev(FileBase, "\") - 1)
FileBase = Mid$(FileBase, InStrRev(FileBase, "\") + 1)
End If
' BaseFile now contains the directory; ensure it exists
If Not My.Computer.FileSystem.DirectoryExists(BaseFile) Then
My.Computer.FileSystem.CreateDirectory(BaseFile)
' Check for versioning and add it if required
If UseVersion AndAlso InStr(FileBase, " v.") = 0 Then FileBase
+= " v." & My.Application.Info.Version.ToString()
#If DEBUG Then
FileBase += " - DEBUG "
#End If
' Set basefile to be the entire file except for the date; this
will potentially change on every open
BaseFile = TrailSlash(BaseFile) & FileBase & " - " &
UCase$(Environ$("USERNAME")) & " on " & UCase$(My.Computer.Name) + " - "
' FileName will be the complete log file name
FileName = BaseFile & Today.ToString(LogFileNameDateStamp) &
".log"
' Open it and set the opened date to today; used by ReOpen
ts = My.Computer.FileSystem.OpenTextFileWriter(FileName, True,
System.Text.Encoding.ASCII)
Opened = Today
' Log the fact that we opened the log file
WriteLog(TypeName(Me) & " '" & FileName & "' Opened")
End Set
End Property
Public Sub WriteLog(Optional ByVal Message As String = "")
' Remove trailing spaces and tabs as they are simply wasted file
space
Message = Message.TrimEnd(" "c, CChar(vbTab), CChar(vbBack),
CChar(vbCr), CChar(vbLf), CChar(vbFormFeed), CChar(vbNullChar),
CChar(vbVerticalTab))
' All writes to the logfile must complete before another thread can
start.
SyncLock LockWriteMessage
If FileName = "" Then Name = My.Application.Info.Title Else
ReOpen()
If Message <> "" Then
ts.WriteLine(Now.ToString(LogFileEntryDTStamp) & vbTab &
Message)
ts.Flush()
Else
' Since there is no reason to flush empty lines, I chose not
to set the AutoFlush property to True.
ts.WriteLine("")
End If
End SyncLock
End Sub
' Check for change of day. This way the logfile for this application
will reopen automatically the first time it is written to on a new day.
' A side effect of this is that if you start and stop the same program
multiple times in the same day, the logfile will be appended to during the
day.
' This is why I implemented the IDisposable interface.
Public Sub ReOpen()
If FileName <> "" AndAlso Opened.Date <> Today Then
SyncLock LockWriteMessage
Opened = Today
FileName = BaseFile & Today.ToString(LogFileNameDateStamp) &
".log"
WriteLog("Day Change Closure")
WriteLog("Log File Closing; new logfile '" & FileName & "'
being opened")
ts.Close()
ts = My.Computer.FileSystem.OpenTextFileWriter(FileName,
True, System.Text.Encoding.ASCII)
WriteLog(TypeName(Me) & " '" & FileName & "' Opened after
Day Change")
End SyncLock
End If
End Sub
Public Function Close() As String
Dim fName As String = FileName
If fName <> "" Then ts.Close()
FileName = ""
Return fName
End Function
#Region " IDisposable Support "
Private disposedValue As Boolean = False ' To detect redundant calls
' IDisposable
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
Const msgDisposing As String = "Logfile being Garbage Collected"
If FileName <> "" Then
Try
WriteLog(msgDisposing)
Close()
Catch ex As Exception
' The framework GC tends to dispose the internal
streamwriter before the class IDisposable interface is called. If you don't
care about this final message
' you can dump the entire IDispose interface.
SyncLock LockWriteMessage
Dim tsClosing As StreamWriter =
My.Computer.FileSystem.OpenTextFileWriter(FileName, True,
System.Text.Encoding.ASCII)
tsClosing.WriteLine(Now.ToString(LogFileEntryDTStamp) &
vbTab & msgDisposing)
tsClosing.Close()
End SyncLock
End Try
End If
Me.disposedValue = True
End Sub
' This code added by Visual Basic to correctly implement the disposable
pattern.
Public Sub Dispose() Implements IDisposable.Dispose
' Do not change this code. Put cleanup code in Dispose(ByVal disposing
As Boolean) above.
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
Protected Overrides Sub Finalize()
On Error Resume Next ' We don't really care that there is an
error, but we don't want this to crash either
Dispose(False)
ts.Dispose()
End Sub
#End Region
End Class