Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Easy C# Exception (Or Whatever) Logging Service

0.00/5 (No votes)
15 Dec 2014 1  
Add a singleton exception logger to your app for easy logging of interesting occurrences in your app

Singular Exception Logger

There are many logging solutions available, and some of them are awesome (such as Log4Net), but I doubt you'll find one that's easier to set up and use than this one.

All you have to do to start logging messages from your app (whether it be for debugging where the app "goes" or just logging exceptions, or whatever) is to add a class to your project named "ExceptionLoggingService" (or whatever name floats your boat).

Note: Although I named it "ExceptionLoggingService", you can use it for anything - not just exceptions. Anyway, here's the entire class:

using System;

namespace Platypusophile
{
    using System.IO;
    using System.Text;

    public class ExceptionLoggingService
    {
        // </ Singleton code
        // private fields
        private readonly FileStream _fileStream;
        private readonly StreamWriter _streamWriter;
        private static ExceptionLoggingService _instance;
        // public property
        public static ExceptionLoggingService Instance
        {
            get
            {
                return _instance ?? (_instance = new ExceptionLoggingService());
            }
        }
        //private constructor
        private ExceptionLoggingService()
        {
            _fileStream = File.OpenWrite(GetExecutionFolder() + "\\EasyAsFallingOffA.log");
            _streamWriter = new StreamWriter(_fileStream);
        }
        // <!-- Singleton code

        public void WriteLog(string message)
        {
            if (!HHSConst.Logging)return;
            StringBuilder formattedMessage = new StringBuilder();
            formattedMessage.AppendLine("Date: " + DateTime.Now.ToString());
            formattedMessage.AppendLine("Message: " + message);
            _streamWriter.WriteLine(formattedMessage.ToString());
            _streamWriter.Flush();
        }

        private string GetExecutionFolder()
        {
            return Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);<span style="font-size: 9pt;"> </span>

Note the "if not logging return" logic at the start of the WriteLog() method; To use this, add a global bool somewhere, such as in a Consts class, so that you can toggle logging:

public static class HHSConsts
{
    public static bool Logging = true;
    . . .

Easy as Falling off a Log File

Now you can call it like so:

ExceptionLoggingService.Instance.WriteLog("Go, Packers!");

Or, more realistically, from inside an exception block:

catch (Exception ex)
{
    String msgInnerExAndStackTrace = String.Format(
        "{0}; Inner Ex: {1}; 
        Stack Trace: {2}", ex.Message, ex.InnerException, ex.StackTrace);
    ExceptionLoggingService.Instance.WriteLog(String.Format
    ("From frmDelivery.ConditionallyPrint():{0}", msgInnerExAndStackTrace));
}

Note that the logging service implements the Singleton pattern, and so you call its public static property "Instance" which allows for JIT creation/instantiation of the class and ensures that there is never more than one instance in memory. You can then call its "WriteLog()" method, which will automatically add the date for you - all you need to supply it is the string you want to have logged.

The file is then saved in the same directory as the .exe, with the name "EasyAsFallingOffA.log" (unless for some strange reason you want to change it to something else). The file (once written to) will contain entries something like this:

Date: 2/19/2009 11:34:10 PM
Message: From HHSDBUtils.SaveAndGetINVDataAsXMLFromTable: SQL logic error or missing database
no such table: INV_3_20090206200112000.xml; Inner Ex: ; 
Stack Trace:    at System.Data.SQLite.SQLite3.Prepare(SQLiteConnection cnn, . 

. .

Bonus Tip

You can get the skinny on exceptions you neglected by adding an application-wide handler like so, such as in Program.cs:

static void Main()
{
    AppDomain.CurrentDomain.UnhandledException += Unhandled;
    Application.Run(new frmMain());
}

static void Unhandled(object sender, UnhandledExceptionEventArgs exArgs)
{
    ExceptionLoggingService.Instance.WriteLog(String.Format
    ("From application-wide exception handler: {0}", exArgs.ExceptionObject));
}

Yet Another Bonus Tip

If you want to also know who was running the program, you can get their name this way:

string userName = System.Security.Principal.WindowsIdentity.GetCurrent().Name;

...and then add that value into the message. That way you can see who is running into which problems, and respond accordingly. You might even have a little fun with it by telling them you see that they did this or that and had such-and-such a problem. If they are ignorant of your programming prowess, they may start looking over their shoulder and searching for hidden cameras, etc.

Now Pay Up!

If you find this tip useful, manifest your undying gratitude by sending me a giant chocolate duckbilled platypus. I will (eventually) forgive you if it's hollow, as I know a solid one might weigh quite a bit and cost you a pretty penny in shipping costs. If more convenient for you, simply send me a 3D printer and a 55-gallon drum of Belgian chocolate, and I'll make the "Choctypus" myself.

Force Augustus Gloop to Morph Into Twiggy

Here's yet another tiplet, free as a bird now (but I'm hoping you're even more moved to supply me my yearned-for Choctypus)*: If you want to prevent your log file from getting too large (it may be a moot point in these days of Gigabytes and Terrabytes for most, but on my Windows CE / Compact Framework every bit counts), you can check its size on startup and delete it at whatever point seems too hefty to you like so (I use 20000 here):

* This is kind of like the snuck-in final scene at the end of a flick, such as the wedding scene in Napoleon Dynamite, that wondrous documentary of Idaho life.

const int MAX_FILESIZE_ALLOWED = 20000;
string uriPath = GetExecutionFolder() + "\\Application.log";
if (System.IO.File.Exists(uriPath))
{
    string logPath = new Uri(uriPath).LocalPath;
    FileInfo f = new FileInfo(logPath);
    long fileSizeInBytes = f.Length;
    if (fileSizeInBytes > MAX_FILESIZE_ALLOWED)
    {
        File.Delete(logPath);
    }
}

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