Logging Your Application for Fun and Profit Part 2
Back in Part1, I discussed logging using dbgview, here in Part 2, I'll move into the EventLog and as a developer, I despise the event log. it's hard to get to, and
isn't as user friendly as it should be. I mentioned already that Admins
LOVE the event log mostly because they have many tools set up to
monitor it and be alerted if something isn't working. This has it's
benefits. Say for instance, that our DeathRayController also connects to
a SQL server. Now if the SQL server goes down, our application may fail
in some way, and that failure will be logged to the event logger. Administrators will know the extent our application is effected by this outage immediately, and they don't have to find out on their own. I've
been around projects where the SQL server will run out of space, or a
change is made and it goes down. Then everyone is opening up
applications and websites to see if it's down too. Did it connect to
that server? Is it even affected? If it didn't write to the event log, then it should be good. No phone calls to you while you're sleeping/watching American Idol. Lets write to the event log.
Writing to the Event Log
Instructions on how to write to the event log are here:
https://support.microsoft.com/kb/307024, so lets use that to add a line
to our method and write to the event log also:
class Logger
{
public static void LogError(string message)
{
Console.WriteLine("ERROR: " + message);
Debug.Write(message, "DeathRayControllerERROR");
if (!EventLog.SourceExists("DeathRayController"))
{
EventLog.CreateEventSource("DeathRayController", "Application");
}
EventLog.WriteEntry("DeathRayController", "ERROR: " + message, EventLogEntryType.Error);
}
}
Here we are checking to see if the DeathRayController exists as a
source, and if not, we create it (the source is really just the name of the application.) Then... We write to it, and specify that
it should go into the event log as an error. Easy-peasy (yeah I went there). If we run this, and pull
open the event log, we can see the entries in there.
There we see an error, when it occured, the source is our DeathRayController. There is an event ID also, and it's optional when writing to the event log. We could use that if we like to give a numerical error to our error, this way we don't have to read the contents. 1 could mean a SQL problem, 2 could mean a memory error, 739 could mean someone had installed the death ray backwards. It's really up to you. I didn't specify an event id.
If we look at one of the errors int he event log, we can see the details of the error we logged...
There is pleanty of room for LOTS of text here, so when writing to the event log, feel free to really add the information you need in there.
Like I said, the event log really isn't for debugging as much as it is for logging, and it's more of an admin thing then a developer tool. It's so easy though to write to it, you might as well just do it. It's great
for administrators who are used to being in there, and there are 3rd party tools that monitor the event log, like EventSentry, or LogRhythm, that can help parse those things out.
Now, event logging is good for things that have HAPPENED, and writing to the event log is good for administrators, but annoying for developers. You know what works fairly decently for developers? Writing to a text file.
A Simple Text File
The best things about text files, is their really, really simple, and
if you have access to the application folder, you can look at the text
file (probably). The problem with text files, is you might not have the
ability write to the folder, system IO problems, and the size of the
text file. Generally, if you DO write to a text file, you'll want to
create a new file based on the date, and you'll want to throw it all in a
try/catch in case you're getting more errors then you can successfully
write. Here is a method that writes errors to the file...
private static void WriteToLogFile(string message)
{
//set the path to something you can write to...
string filePath = string.Format(@"C:\DeathRayControllerLog_{0}-{1}-{2}.txt", DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day);
System.IO.StreamWriter file = null;
if (filePath == null)
{
Console.WriteLine("FilePath must be set in order to write to logs.");
return;
}
try
{
file = new System.IO.StreamWriter(filePath, true);
file.WriteLine(message + "\n");
}
catch (System.IO.PathTooLongException)
{
Console.WriteLine("A PathTooLongException occured. Maybe try shortening the path, buddy.");
}
catch (System.IO.IOException iox)
{
Console.WriteLine("An IOException occured. Something is wrong with my ability to write the file.\n" + iox.ToString());
}
catch (Exception ex)
{
Console.WriteLine("Writing to the file failed. Here's what happened:");
Console.WriteLine();
Console.WriteLine(ex.ToString());
}
finally
{
if (file != null)
{
file.Close();
}
}
}
Then we simply add another item to our method...
public static void LogError(string message)
{
Console.WriteLine("ERROR: " + message);
Debug.Write(message, "DeathRayControllerERROR");
if (!EventLog.SourceExists("DeathRayController"))
{
EventLog.CreateEventSource("DeathRayController", "Application");
}
EventLog.WriteEntry("DeathRayController", "ERROR: " + message, EventLogEntryType.Error);
WriteToLogFile("ERROR: " + message);
}
Notice in the WriteToLogFile class, I catch a bunch of different exceptions, this is
important! You don't want your logging to cause even MORE errors then
the application already has. Writing to a text file can cause all sorts of problems with security, naming, the file already being opened, the file being gone, etc. It's best to just catch and ignore then introduce more problems. However if everything is working well, having a generic text file to see errors can be immensely helpful, especially if your logging more then just
errors. Thats right MORE THEN JUST ERRORS! I'll talk about other types of logging in Part 3.