Click here to Skip to main content
15,861,125 members
Articles / Desktop Programming / Windows Forms
Article

Log Monitor

Rate me:
Please Sign up or sign in to vote.
4.71/5 (22 votes)
6 Jun 20074 min read 124.4K   6.4K   98   27
This article describes how to write an application to monitor text log files

Screenshot - LogMonitorScreen.jpg

Introduction

I often need to watch text-based log files for services or IIS logs. I got tired of having to refresh the file in my editor or having to close and re-open the file to see the latest changes. So, I wrote a tool that would do the work for me and show me the latest additions to a log file continuously. The application is pretty full-featured. It supports the following:

  • Multiple log files can be open at the same time.
  • File names can be passed as arguments to the application to be loaded at startup.
  • A TabControl is used to switch between the log files being monitored.
  • Files can be dropped onto the application.
  • Logs can be updated via a timer or immediately using FileSystemWatcher.
  • Updates can be paused.
  • Only the lines added to the log since the last update are read in to optimize performance.
  • If the file is too large then only the end of the log is read in.
  • Correctly handles log files that only terminate lines with linefeed.
  • Settings and window position are saved in the configuration file.

Using the code

To work with the source code, just unzip the Source Files and open the LogMonitor.sln solution file. This was written using .NET 2.0 entirely in C#.

Points of interest

LogMonitorControl user control

The main worker class in this application is LogMonitorControl, which is a user control that watches a single log file. A TabControl is used to hold multiple instances of LogMonitorControl.

Threading concerns

One tricky bit was that the LogMonitorControl can use a Timer or a FileSystemWatcher to monitor the log file. These behave differently in terms of threading. When using the Timer, the timer tick callbacks occur on the main thread. However, when using the FileSystemWatcher method, the callback happens on a different thread. So, updating the child controls involved checking whether or not Invoke should be used via the InvokeRequired property. Anonymous delegates help greatly with this. However, if a lot of code is to be executed for a control, then it is also convenient to write a method that performs those actions. Then either Invoke that method or call it directly. Below is an example of where this is needed. Note that the method DoScrollToEnd is a method of the LogMonitorControl class and not a member of the control Invoking the method:

C#
public void ScrollToEnd()
{
    if (_textBoxContents.InvokeRequired)
    {
        _textBoxContents.Invoke(new MethodInvoker(DoScrollToEnd));
    }
    else
    {
        DoScrollToEnd();
    }
}

Drag & drop support
(Well, just drop support really.)

Adding drop support was very easy and consisted of only 2 methods. The code is as follows:

C#
private void tabControl_DragDrop(object sender, DragEventArgs e)
{
    // Accept files dropped and create new a tab each file.
    IDataObject data = e.Data;
    // Only accept file drops
    if (data.GetDataPresent(DataFormats.FileDrop))
    {
        // Get the list of files dropped and create tabs for each
        string[] filesToDrop = 
            (string[])e.Data.GetData(DataFormats.FileDrop, false);
        for (int idx = 0; idx < filesToDrop.Length; idx++)
        {
            MonitorNewFile(filesToDrop[idx]);
        }
    }
}

private void tabControl_DragEnter(object sender, DragEventArgs e)
{
    IDataObject data = e.Data;
    // Only accept file drops
    if (data.GetDataPresent(DataFormats.FileDrop))
    {
        e.Effect = DragDropEffects.Copy;
    }
    else
    {
        e.Effect = DragDropEffects.None;
    }
}

FileSystemWatcher

The FileSystemWatcher class is found in the System.IO namespace and is used to monitor changes to a file or any file in a directory. The constructor takes a path and a filename pattern. The LogMonitor application calls the constructor with a filename for the pattern to monitor a single file. We are interested in all of the change events that this class can raise, so we sign up for all of them. We could actually track this file through renames and continue to monitor the log file, but I choose to simply keep watching the same file. Then if the file is renamed back, we will detect that. Similarly, if another file is created with the same filename, that will also be detected. There is one thing that is not completely obvious about the FileSystemWatcher class. That is, if you sign up for the file events you will never receive them unless you set the property EnableRaisingEvents to true.

C#
_watcher = new System.IO.FileSystemWatcher(path, baseName);
FileSystemEventHandler handler = new FileSystemEventHandler(watcher_Changed);
_watcher.Changed += handler;
_watcher.Created += handler;
_watcher.Deleted += handler;
_watcher.Renamed += watcher_Renamed;
// Without setting EnableRaisingEvents nothing happens
_watcher.EnableRaisingEvents = true;

Open file with lowest amount of locking

Some applications keep the log file open during execution, like IIS. To give the LogMonitor the best chance of working with these types of applications, it opens the log file with the friendliest settings possible. The easiest way to read a text file in .NET is to use the File.ReadAllText() method. However, this does not open the file with the proper sharing flags. So, I open the file using File.Open and specify the access and sharing modes. Then open a StreamReader and use ReadToEnd on that stream. The code for reading the file is shown below, with some lines that are irrelevant to this point having been removed:

C#
string newFileLines = "";
using (FileStream stream = File.Open(_fileName, 
    FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
    using (StreamReader reader = new StreamReader(stream))
    {
        newFileLines = reader.ReadToEnd();
    }
}

History

  • 5 June, 2007 -- Original version posted
  • 6 June, 2007 -- Version 1.0.0.1
    • Fixed bug with trimming text for large files. (Thanks for the catch s_mom).

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
I have been developing .NET applications since 2001 and have been working in software development since 1989.

Comments and Discussions

 
QuestionRemarks Pin
Member 1284912330-Apr-17 20:25
Member 1284912330-Apr-17 20:25 
GeneralMy vote of 2 Pin
Member 1284912330-Apr-17 20:23
Member 1284912330-Apr-17 20:23 
Praiseawesome dude! Pin
Member 123628492-Nov-16 15:15
professionalMember 123628492-Nov-16 15:15 
GeneralSmall bug Pin
Mihai Matei7-Dec-13 9:18
Mihai Matei7-Dec-13 9:18 
General[Message Removed] Pin
immetoz4-Oct-08 2:01
immetoz4-Oct-08 2:01 
NewsI've made some 'enhancements' Pin
Greig Stewart19-May-08 23:37
Greig Stewart19-May-08 23:37 
GeneralText Encoding Pin
chinkuanyeh16-Oct-07 17:23
chinkuanyeh16-Oct-07 17:23 
GeneralGreat tool Pin
DzoIg28-Jun-07 1:47
DzoIg28-Jun-07 1:47 
AnswerRe: Great tool Pin
Vance Kessler28-Jun-07 2:05
Vance Kessler28-Jun-07 2:05 
GeneralRe: Great tool Pin
DzoIg28-Jun-07 3:15
DzoIg28-Jun-07 3:15 
GeneralRe: Great tool Pin
netedk14-Nov-08 8:05
netedk14-Nov-08 8:05 
GeneralRe: Great tool Pin
Vance Kessler14-Nov-08 8:15
Vance Kessler14-Nov-08 8:15 
GeneralSimple version for beginners Pin
Hellacious15-Jun-07 1:52
Hellacious15-Jun-07 1:52 
AnswerRe: Simple version for beginners Pin
Vance Kessler18-Jun-07 9:49
Vance Kessler18-Jun-07 9:49 
GeneralRe: Simple version for beginners Pin
Antrys7-Jul-15 14:35
Antrys7-Jul-15 14:35 
GeneralNice Tool & excellent coding Pin
abhi131012-Jun-07 3:52
abhi131012-Jun-07 3:52 
Generallittle problem Pin
StM0n6-Jun-07 2:27
StM0n6-Jun-07 2:27 
AnswerRe: little problem Pin
Vance Kessler6-Jun-07 3:11
Vance Kessler6-Jun-07 3:11 
GeneralExcellent!!!!! Pin
Septimus Hedgehog6-Jun-07 1:43
Septimus Hedgehog6-Jun-07 1:43 
GeneralI like it! Pin
CoderSoup5-Jun-07 11:44
CoderSoup5-Jun-07 11:44 
GeneralNice Work Pin
suchnight5-Jun-07 11:09
suchnight5-Jun-07 11:09 
QuestionTail? Pin
dotnetangel5-Jun-07 9:25
professionaldotnetangel5-Jun-07 9:25 
AnswerRe: Tail? Pin
Mackster2116-Jun-07 1:31
Mackster2116-Jun-07 1:31 
AnswerRe: Tail? Pin
Vance Kessler6-Jun-07 1:55
Vance Kessler6-Jun-07 1:55 
GeneralRe: Tail? Pin
dotnetangel6-Jun-07 12:21
professionaldotnetangel6-Jun-07 12:21 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.