Logging in C#

I wrote up a very simple C# class that provides logging for C# applications since the C# Logger on sourceforge is still in alpha (and doesn’t appear to be active) and the .NET framework doesn’t seem to provide normal text file logging outside of the EventLog (correct me if I’m wrong):

using System;
using System.IO;
namespace com.ignitionlabs.logging {  
  public class Logger {
    private static int _ALL = 100;
    private static int _INFO = 75;
    private static int _ERROR = 50;
    private static int _OFF = 0;
    private static String logDirectory = System.Configuration.ConfigurationSettings.AppSettings["logging.directory"].ToString();
    public static int ALL {
      get { return _ALL; }
    }
    public static int ERROR {
      get { return _ERROR; }
    }
    public static int INFO {
      get { return _INFO; }
    }
    public static int OFF {
      get { return _OFF; }
    }
    public static void append(String message, int level) {
      int logLevel = _OFF;
      String strLogLevel = System.Configuration.ConfigurationSettings.AppSettings["logging.level"].ToString();
      switch(strLogLevel) {
        case "ALL":
          logLevel = _ALL;
          break;
        case "ERROR":
          logLevel = _ERROR;
          break;
        case "INFO":
          logLevel = _INFO;
          break;
        default:
          logLevel = _OFF;
          break;
      }
      if (logLevel >= level) {
        DateTime dt = DateTime.Now;
        String filePath = logDirectory + dt.ToString("yyyyMMdd") + ".log";
        if (!File.Exists(filePath)) {
          FileStream fs = File.Create(filePath);
          fs.Close();
        }
        try {
          StreamWriter sw = File.AppendText(filePath);
          sw.WriteLine(dt.ToString("hh:mm:ss") + "|" + message);
          sw.Flush();
          sw.Close();
        } catch (Exception e) {
          Console.WriteLine(e.Message.ToString());
        }
      }
    }
  }
}

After compiling, you’ll need to add 2 elements to your <appsettings> in web.config:

<add key=”logDirectory” value=”c:\myapp\logs\” />
<add key=”logLevel” value=”ALL|INFO|ERROR|OFF” />

and then you can use the class like this:

Logger.append(“your application message…”, Logger.ALL);

As always, I’m interested in any design flaws or critiques.

17 thoughts on “Logging in C#”

  1. Looks good… just a couple of comments:

    * You might want to use an enum for your levels.

    * Is there a reason you’re loading the log level from the config file every time append is called? Seems like this could get expensive if there are tons of logging calls. Same with opening/closing the StreamWriter; why not keep it around?

    * If you do decide to keep the StreamWriter around, you probably need to put a lock{} around the calls to it–it’s not guaranteed to be threadsafe.

    * Instead of dt.ToString(“yyyy”) + dt.ToString(“MM”) + dt.ToString(“dd”), how about dt.ToString(“yyyyMMdd”)?

    * It might be cool to be able to add your own log listeners (like log4j’s appenders). That way you could log to multiple sinks at once (database, event log, etc.). I’ve previously tackled this with .NET events; I declare a static event whose EventArgs include the message’s priority/level, text, and date/time, and anyone who cares can just register for that event.

    * I sympathize with you but I think most C# developers would appreciate it if your append method began with a capital “A”… 🙂

    * What’s Ignition Labs? 🙂

    -joe

  2. I wrote a logging package too. I did it pretty recently, and if I had known that you were interested, I probably would’ve asked if you wanted to collaborate. Anyway, if you think the code’s useful, have fun with it. It’s at http://sourceforge.net/projects/nspring . It offers good speed, multiple outputs, etc. but the configuration section is still not complete. Also in the works is a centralized logging application. The docs are in the single .zip file with all the code.

  3. Tony,

    If anything I useed a static method because it was easier to code and to use. If it matters, both log4j and log4net use a the Factory pattern to get an instance of a logger and then you can log. With the code snippet above, you don’t need an instance, you can simply fire log.append() whenever you want.

  4. Why don’t you use the Trace class provided by .NET? It provides the same functionality as your code (you can attach a TextWriterTraceListener to write to file). In addition, you can disable all trace output with a compiler flag (trace calls are included by default in Debug and Release builds).

    Just look up the Trace class in the documentation, this should give you all the info you need.

  5. wir sind ihr partner in sachen computer und internet. wir entwickeln fã¼r sie individuelle software nur auf sie zugeschnitten. wir machen ihr webdesign und optimieren ihre webseite, damit sie eine gute positionierung bei suchmaschinen bekommen.

  6. “you’ll need to add 2 elements to your in web.config”? I assume you mean for web apps? ASP.NET? What about for Windows apps? It’d be great if you explain what this meant and how the code works. And, yes, capitalize Append!

  7. Hello, this is the class that inspired me to write advanced logging classes! I have written classes that can easily switch from database or file logging, thus multiple logging levels are enabled (just as your class), and it is more object-oriented. If someone is looking for advanced OOP logging classes – you can check my post Advanced flexible Logger in C# and tell me what you think about it.

  8. System.Configuration.ConfigurationSettings.AppSettings[“logging.directory”].ToString();

    System.Configuration.ConfigurationSettings.AppSettings[“logging.level”].ToString();

    Do not match: “After compiling, you’ll need to add 2 elements to your in web.config:

    I’m a novice and this mixed me up for a while!

  9. I think a better refactoring would make code look like:

    public class Logger
    {

    private static string logDirectory = ConfigurationManager.AppSettings["logDirectory"];

    private static string strLogLevel = ConfigurationManager.AppSettings["logLevel"];

    private static Loglevel logLevel = Loglevel.Off;

    static Logger()
    {
    switch (strLogLevel)
    {
    case "ALL":
    logLevel = Loglevel.All;
    break;

    case "ERROR":
    logLevel = Loglevel.Error;
    break;

    case "INFO":
    logLevel = Loglevel.Info;
    break;

    default:
    logLevel = Loglevel.Off;
    break;
    }
    }

    public static void Append(String message, Loglevel level)
    {
    if (logLevel >= level)
    {
    DateTime dt = DateTime.Now;
    String filePath = logDirectory + dt.ToString("yyyyMMdd") + ".log";

    if (!File.Exists(filePath))
    {
    FileStream fs = File.Create(filePath);
    fs.Close();
    }

    try
    {
    File.AppendAllText(filePath, string.Format("{0} - {1}", dt.ToString("hh:mm:ss"), message));
    }
    catch (Exception e)
    {
    Console.WriteLine(e.Message.ToString());
    }
    }
    }
    }

Leave a Reply

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