Miscellaneous Debris

Avner Kashtan's Frustrations and Exultations

November 2007 - Posts

System.Diagnostics.EventLogEntry and the non-equal Equals.

Just a quick heads-up in case you're stumped with this problem, or just passing by:

The System.Diagnostics.EventLogEntry class implements the Equals method to check if two entries are identical, even if they're not the same instance. However, contrary to best practices, it does NOT overload the operator==, so these two bits of code will behave differently:

EventLog myEventLog = new EventLog("Application");
EventLogEntry entry1 = myEventLog.Entries[0];
EventLogEntry entry2 = myEventLog.Entries[0];

bool correct = entry1.Equals(entry2);
bool incorrect = entry1 == entry2;

After running this code, correct will be true while incorrect will be false.

Good to know, if you're reading event logs in your code.

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:         }
More Posts