Introduction
This example is a simple class that provides a method to write to a log file and control its size. It lets you set the maximum number of lines that will be maintained in the log. Once the max number of lines have been reached then the oldest entry is taken off the top each time a new line is added.
Background
Several years ago I worked with a team that was dealing with a serious customer issue where errors being logged over several years had actually filled the systems hard drive completely. Lesson learned!
For me it is important that programs elegantly log any errors - especially services that have no UI where there is no place to display errors for the users. It's also important to make sure the logging doesn't just go on forever or you, at the very least, will be wasting a lot of disc space; a worst you could wind up using up all of the available disc space and cause serious problems for the end user. This class, written in VB.NET, lets you define the output log file name and the maximum number of lines to maintain. The default is 99 lines.
Using the code
To use this class create a new class in your project and then cut and past the class code below into the new class (replacing everything).
You can then create the ErrorLogger object as follows:
Dim MyLogger as New ErrorLogger(MyLogfilename, 150)
There are two methods in this class: Logit
and MakeEventLogEntry
. MakeEventLogEntry
is for adding an entry to the system Event Viewer Application log. You can either make a separate call to MakeEventLogEntry
, or whenever you call the Logit
method you can set the AddToSystemApplicationLog
flag to true and any message you place into your own log file will be added to the System Application log. The flag is optional and defaults to False
. This uses the optional parameter feature offered in VB.NET (I know many of you think that this is just syntactacal candy - but it requires less code to do this than to overload the method).
There are two properties: LogFilename
and MaxLogLines
. Both have defaults set (explained in the Intellisense). You can set these when instantiating an object from the class using the New()
keyword, or you can set them separately.
Here is the class - including Intellisense.
Imports System.IO
Public Class ErrorLogger
Sub New(ByVal LogFileName As String, ByVal MaxLogLines As Integer)
Me.LogFileName = New FileInfo(LogFileName)
Me.MaxLogLines = MaxLogLines
End Sub
Sub New(ByVal LogFileName As String)
Me.LogFileName = New FileInfo(LogFileName)
End Sub
Sub New()
End Sub
Public Property MaxLogLines As Integer = 99
Private _LogFileName As FileInfo = New FileInfo(Path.Combine(My.Application.Info.DirectoryPath, _
System.Reflection.Assembly.GetEntryAssembly().GetName().Name & ".log"))
Public Property LogFileName As FileInfo
Get
Return _LogFileName
End Get
Set(value As FileInfo)
If Not value.Directory.Exists Then
Throw New ArgumentException("Folder/Path for specified log file name does not exist!")
End If
_LogFileName = value
End Set
End Property
Public Sub Logit(ByVal Message As String, Optional ByVal AddToSystemApplicationLog As Boolean = False)
Static LogLines As New List(Of String)
If LogLines.Count = 0 Then
If Me.LogFileName.Exists Then
Try
LogLines = IO.File.ReadAllLines(Me.LogFileName.FullName).ToList
Catch ex As Exception
Try
MakeEventlogEntry("Cannot read log file!")
Catch exx As Exception
Exit Sub End Try
Exit Sub End Try
End If
End If
If Message.EndsWith(Environment.NewLine) Then
Message = Message.Substring(0, Message.Length - 2)
End If
Message = System.DateTime.Now & " " & Message
LogLines.Add(Message)
Do While LogLines.Count > Me.MaxLogLines
LogLines.RemoveAt(0)
Loop
Try
IO.File.WriteAllLines(Me.LogFileName.FullName, LogLines)
If AddToSystemApplicationLog Then
MakeEventlogEntry(Message)
End If
Catch ex As Exception
Try
MakeEventlogEntry("Cannot write to log file!")
Catch exx As Exception
Exit Sub End Try
Exit Sub End Try
End Sub
Public Sub MakeEventlogEntry(Message As String)
Dim sSource As String = My.Application.Info.ProductName
Dim sLog As String = "Application"
Dim sMachine As String = "."
Dim ESCD As New EventSourceCreationData(sSource, sLog)
If Not EventLog.SourceExists(sSource, sMachine) Then
System.Diagnostics.EventLog.CreateEventSource(ESCD)
EventLog.WriteEntry(sSource, Message, EventLogEntryType.Error)
End If
End Sub
End Class
You will notice there are three New()
overloads. Since the LogFilename
and MaxLogLines
properties both have defaults these overloaded New()
methods let you accept either, none or both of them.
Points of Interest
Adding the MakeEventlogEntry
method may be overkill, but I use this class when I create services - and I think most sophisticated users expect service errors to be logged in the Event Log.
The number of entries in the log file should be set only once at run-time and never changed. If it is the program will take care of it, but its more likely you may confuse your user if they visit the log file often.
Scaling
As another Code Project contributor has aptly pointed out; this method of logging does not scale up very much. If your logging needs exceed about 5 to 10k (gut numbers here...) of logging then you should consider alternate methods. This class essentially rewrites the entire log file each time, so there would be a performance and memory cost associated with it for large logs. In the example above I have limited the log to 150 lines, and the default in the class is 99. These numbers will have little impact on most any application that will benefit from this smaller logging requirement. If, however, your application needs 5-thousand lines - this is not the method for you.