Displaying live log file contents

I’m writing some benchmarking code, which involves a Console application calling a COM+ hosted process and measuring performance. I want to constantly display results on my active console, but since some of my code is running out-of-process, I can’t really write directly to the console from all parts of the system. Not to mention the fact that I want it logged to a file as well.

So I cobbled together a quick Log class that does two things – it writes to a shared log file, keeping no locks so several processes can access it (I do serialize access to the WriteLine method itself, though). I don’t mind the overhead of opening/closing the file every time, since this isn’t production code.

The second method is the interesting one – it monitors the log file and returns every new line that is appended to it. If no lines are available, it will block until one is reached. The fun part was using the yield return keyword, which I’ve been looking for an excuse to use for quiet a while now.

Note that there are many places this code can go wrong or should be improved. There is no way to stop it running, only when the application is stopped. I bring this as the basic idea, and it can be cleaned up and improved later:

   1: public static IEnumerable<string> ReadNextLineOrBlock()
   2:         {
   3:             // Open the file without locking it.
   4:             using (FileStream logFile = new FileStream(Filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
   5:             using (StreamReader reader = new StreamReader(logFile))
   6:             {
   7:                 while (true)
   8:                 {
   9:                     // Read the next line.
  10:                     string line = reader.ReadLine();
  11:                     if (!string.IsNullOrEmpty(line))
  12:                     {
  13:                         yield return line;
  14:                     }
  15:                     else
  16:                     {
  17:                         Thread.Sleep(100);
  18:                     }
  19:                 }
  20:             }
  21:         }

This method can now be called from a worker thread:

 

   1: private static void StartListenerThread()
   2:         {
   3:             Thread t = new Thread(delegate()
   4:             {
   5:                 while (true)
   6:                 {
   7:                     foreach (string line in Log.ReadNextLineOrBlock())
   8:                     {
   9:                         // I added some formatting, too.
  10:                         if (line.Contains("Total"))
  11:                             Console.ForegroundColor = ConsoleColor.Green;
  12:                         
  13:                         Console.WriteLine(line);
  14:  
  15:                         Console.ForegroundColor = ConsoleColor.White;
  16:                     }
  17:                 }
  18:             });
  19:  
  20:             t.Start();
  21:         }

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.