473,387 Members | 1,398 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes and contribute your articles to a community of 473,387 developers and data experts.

Simple Sub/Class to write to a limited-length log file (AKA Circular buffer file)

!NoItAll
297 100+
I like to make sure my programs (especially services that have no UI at all) log errors in a meaningful way. Adding a log file function is very easy, but unfortunately unless you take precautions a log file can simply grow forever.

Some years ago I worked with a team and we discovered that a major issue at a customer site was simply because logging used up all of the available disk space.
Recently I wrote a small service. I wanted to log any errors, but needed to make sure the log file didn't grow forever.

I came up with the following code:
Expand|Select|Wrap|Line Numbers
  1.    Private Sub Logit(ByVal Message As String, Optional MaxEntries As Integer = 99)
  2.         Static LogLines As New List(Of String)
  3.         Static LogFile As New FileInfo(My.Application.Info.DirectoryPath & "\Sandbox.log")
  4.         If LogLines.Count = 0 Then
  5.             If LogFile.Exists Then
  6.                 Try
  7.                     LogLines = IO.File.ReadAllLines(LogFile.FullName).ToList
  8.                 Catch ex As Exception
  9.                     Exit Sub  'there's nothing we can do really...
  10.                 End Try
  11.             End If
  12.         End If
  13.  
  14.         'clean up the message
  15.         If Message.EndsWith(Environment.NewLine) Then
  16.             Message = Message.Substring(0, Message.Length - 2)
  17.         End If
  18.         Message = System.DateTime.Now & "     " & Message
  19.         LogLines.Add(Message)
  20.  
  21.         'make sure we keep only MaxEntries entries
  22.         Do While LogLines.Count > Me.MaxLogLines
  23.             LogLines.RemoveAt(0)
  24.         Loop
  25.  
  26.         Try
  27.             IO.File.WriteAllLines(LogFile.FullName, LogLines)
  28.         Catch ex As Exception
  29.             'There's no where to log it so just ignore error
  30.         End Try
  31.  
  32.     End Sub
  33.  
This sub simply allows you to send a message to a log file and limit the number of lines that will ever be in the log. By dafault it is 99 lines. When you add a 100th line the top one is trimmed off. This means the log will not grow infinitely, and will only have as many lines as you want.

When using this routine I recommend you do not use a "magic" number each time it is called (e.g. Logit(MyMessage, 150)). Instead use a const (e.g. Logit(MyMessage, MY_MAX_LOG_ENTRIES)).

Calling the routine with different numbers could cause very confusing results. I also don't like how the log file name is created in the sub. But for small programs this is simple and straight-forward.

A better way to do this would be to create a class that forces you to initialize it to the max entries and filename - that would be cleaner and would look like this:
Expand|Select|Wrap|Line Numbers
  1. Imports System.IO
  2.  
  3. Public Class LimitLog
  4.  
  5.     Sub New(ByVal MaxLogLines As Integer, LogFileName As String)
  6.         Me.MaxLogLines = MaxLogLines
  7.         Me.LogFileName = New FileInfo(LogFileName)
  8.     End Sub
  9.  
  10.     Sub New(LogFileName As String)
  11.         Me.LogFileName = New FileInfo(LogFileName)
  12.     End Sub
  13.  
  14.     Public Property MaxLogLines As Integer = 99
  15.     Public Property LogFileName As FileInfo
  16.  
  17.     Public Sub Logit(ByVal Message As String)
  18.         Static LogLines As New List(Of String)
  19.         If LogLines.Count = 0 Then
  20.             If Me.LogFileName.Exists Then
  21.                 Try
  22.                     LogLines = IO.File.ReadAllLines(Me.LogFileName.FullName).ToList
  23.                 Catch ex As Exception
  24.                     Exit Sub  'there's nothing we can do really...
  25.                 End Try
  26.             End If
  27.         End If
  28.  
  29.         'clean up the message
  30.         If Message.EndsWith(Environment.NewLine) Then
  31.             Message = Message.Substring(0, Message.Length - 2)
  32.         End If
  33.         Message = System.DateTime.Now & "     " & Message
  34.         LogLines.Add(Message)
  35.  
  36.         'make sure we keep only MaxEntries entries
  37.         Do While LogLines.Count > Me.MaxLogLines
  38.             LogLines.RemoveAt(0)
  39.         Loop
  40.  
  41.         Try
  42.             IO.File.WriteAllLines(Me.LogFileName.FullName, LogLines)
  43.         Catch ex As Exception
  44.             'There's no where to log it so just ignore error
  45.         End Try
  46.  
  47.     End Sub
  48.  
  49. End Class
  50.  
Using this class is easy; just instantiate an object as follows:

Friend MyLogger As New LimitLog(150, MyLogFileName)
or
Friend MyLogger As New LimitLog(MyLogFileName)

Notice the class has two (overloaded) New subs. One allows you to initialize the object with both the maximum number of entries and the logs filename. The other just gets the filename and uses the default of 99 entries.

Notice there is no New() sub (without parameters) - this forces you to set either the filename and the maximum number of lines or just the filename when you create the object. This is neater and cleaner - far less prone to errors. Now each call to MyLogger.Logit is just the message and it will be added to the end of the log file.

A note on error checking
You may wish to put in a little more error checking. Notice however that the two error checks I make simply fall-through and are ignored - that's because this is a log file routine intended to log errors - so if there is an error inside of it - well, there's nowhere else to log an error...

Of course - improvements to this code are very welcome - you can post right here.

I've included the class as a zip file for the ultra lazy. Enjoy!
Attached Files
File Type: zip LimitLog.zip (674 Bytes, 201 views)
Feb 2 '13 #1
1 5493
!NoItAll
297 100+
I just updated the code above to do a better job of limiting the number of lines in the log to what the user specifies. I changed the section that removes the top lines that was:

Expand|Select|Wrap|Line Numbers
  1.         'make sure we keep only MaxEntries entries
  2.         If LogLines.Count > Me.MaxLogLines
  3.             LogLines.RemoveAt(0)
  4.         End If
  5.  
To a Do Loop just in case extra lines get into the log. They shouldn't, but who knows. Now the code will continue to remove lines until only the MaxLogLines are in the log by replacing the code above with:

Expand|Select|Wrap|Line Numbers
  1.         'make sure we keep only MaxEntries entries
  2.         Do While LogLines.Count > Me.MaxLogLines
  3.             LogLines.RemoveAt(0)
  4.         Loop
  5.  
Feb 3 '13 #2

Sign in to post your reply or Sign up for a free account.

Similar topics

1
by: Brett | last post by:
We have an application where the iusr_<srvr> has write NTFS permissions to a folder under the wwwroot (i.e. wwwroot\folder) and also there is a SQL Server database where we must give the...
8
by: Dan | last post by:
Using XML::Simple in perl is extreemly slow to parse big XML files (can be up to 250M, taking ~1h). How can I increase my performance / reduce my memory usage? Is SAX the way forward?
8
by: M Jared Finder | last post by:
I'm confused. XML looks to be extremely simple to read and write (so simple that I feel confidant I could program serialization and deserailization from a DOM document in an about an hour), yet I...
10
by: JustSomeGuy | last post by:
I have a few classes... class a : std::list<baseclass> { int keya; }; class b : std::list<a> { int keyb;
13
by: Stumped and Confused | last post by:
Hello, I really, really, need some help here - I've spent hours trying to find a solution. In a nutshell, I'm trying to have a user input a value in form's textfield. The value should then be...
1
by: johnlim20088 | last post by:
Hi, I have a 1)asp net page -> write.aspx in this page, i simple write a line -> Response.write("try get me"); then i have another page called go.aspx
14
by: ap.sakala | last post by:
Hello, How the heck should I make this simple summering of a data without a submit button? Like in an excel sheet I would like to have a couple of cells in a column and as soon the visitor...
176
by: nw | last post by:
Hi, I previously asked for suggestions on teaching testing in C++. Based on some of the replies I received I decided that best way to proceed would be to teach the students how they might write...
7
by: laptopia | last post by:
I need to build, very quickly, implement a form that will add to a database two text fields and store store an image associated with this record. All my experience with this is from ASP and...
1
by: BobLewiston | last post by:
In Windows XP Pro, in addition to an administrator account, I also have a limited account for going online. (Yes, I also take virtually all of the other recommended precautions against malware.) ...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.