It's easy to create a custom logging framework to log your .Net application's errors and events to a flat file, a database, or the event log Credit: Kungfuman You will often want to log events or errors as they occur in your .Net application. To do this, you could take advantage of one of the many popular logging frameworks available, or you could design and develop your own logging framework. In this article we’ll see how we can design and develop our own logging framework with ease, and walk through the steps to build a simple logger in C#. First off, you will need to understand the log targets—the various places where the data could be logged. Let’s assume that we will log the data to flat files, a database, and the event log. The following enumeration defines the log targets we would use in this simple framework. public enum LogTarget { File, Database, EventLog } C# logger classes The next step is to design and implement the classes. We will use three distinct classes—namely, FileLogger, DBLogger, and EventLogger—to log data to a file, a database, and the event log respectively. All of these classes should inherit the abstract base class named LogBase. Here is how these classes are organized. public abstract class LogBase { public abstract void Log(string message); } public class FileLogger : LogBase { public string filePath = @”D:IDGLog.txt”; public override void Log(string message) { using (StreamWriter streamWriter = new StreamWriter(filePath)) { streamWriter.WriteLine(message); streamWriter.Close(); } } } public class DBLogger : LogBase { string connectionString = string.Empty; public override void Log(string message) { //Code to log data to the database } } public class EventLogger: LogBase { public override void Log(string message) { EventLog eventLog = new EventLog(“”); eventLog.Source ="IDGEventLog"; eventLog.WriteEntry(message); } } I have left the DBLogger class incomplete. I will leave it to you to fill in the appropriate code to log your messages to the database. As you can see, all three of the classes – FileLogger, EventLogger, and DBLogger – extend the abstract base class LogBase. The abstract base class LogBase declares the abstract method called Log(). The Log() method accepts a string as the parameter; this string is what will be logged to a file or a database or the event log. The C# LogHelper class Now let’s create a helper class that can be used to invoke the respective logger based on the parameter passed. This helper class will be used to simplify the calls to the Log() method in each of the logger classes. The following code snippet illustrates this helper class. public static class LogHelper { private static LogBase logger = null; public static void Log(LogTarget target, string message) { switch(target) { case LogTarget.File: logger = new FileLogger(); logger.Log(message); break; case LogTarget.Database: logger = new DBLogger(); logger.Log(message); break; case LogTarget.EventLog: logger = new EventLogger(); logger.Log(message); break; default: return; } } } The Log() method of the LogHelper class accepts a string and an instance of the LogTarget enumeration as parameters. It then uses a switch: case construct to determine the target where the text message will be logged. Synchronizing calls to the C# Log method Oops! We forgot to synchronize the calls to the respective Log() methods. To do this, we need to use the lock keyword in the Log() method of each of the logger classes and incorporate the appropriate code to synchronize those Log() methods. Refer to the LogBase class given below. We have incorporated a protected member that will be used to apply the lock in the Log() method of each of the derived classes. Here are the modified versions of these classes. public abstract class LogBase { protected readonly object lockObj = new object(); public abstract void Log(string message); } public class FileLogger : LogBase { public string filePath = @”D:IDGLog.txt”; public override void Log(string message) { lock (lockObj) { using (StreamWriter streamWriter = new StreamWriter(filePath)) { streamWriter.WriteLine(message); streamWriter.Close(); } } } } public class EventLogger : LogBase { public override void Log(string message) { lock (lockObj) { EventLog m_EventLog = new EventLog(“”); m_EventLog.Source ="IDGEventLog"; m_EventLog.WriteEntry(message); } } } public class DBLogger : LogBase { string connectionString = string.Empty; public override void Log(string message) { lock (lockObj) { //Code to log data to the database } } } You can now call the Log() method of the LogHelper class and pass the log target and the text message to log as parameters. class Program { static void Main(string[] args) { LogHelper.Log(LogTarget.File, “Hello”); } } If you ever need to log the text message to a different log target, you would simply pass the appropriate log target as a parameter to the Log() method of the LogHelper class. There are many ways you could improve this logging framework. You could implement asynchrony and a queue so that when large numbers of messages arrive, the logger can process these messages asynchronously without having to block the current thread. You may also want to implement message criticality levels, such as informational messages, warning messages, error messages, and so on. Related content feature What is Rust? Safe, fast, and easy software development Unlike most programming languages, Rust doesn't make you choose between speed, safety, and ease of use. Find out how Rust delivers better code with fewer compromises, and a few downsides to consider before learning Rust. By Serdar Yegulalp Nov 20, 2024 11 mins Rust Programming Languages Software Development how-to Kotlin for Java developers: Classes and coroutines Kotlin was designed to bring more flexibility and flow to programming in the JVM. Here's an in-depth look at how Kotlin makes working with classes and objects easier and introduces coroutines to modernize concurrency. By Matthew Tyson Nov 20, 2024 9 mins Java Kotlin Programming Languages analysis Azure AI Foundry tools for changes in AI applications Microsoft’s launch of Azure AI Foundry at Ignite 2024 signals a welcome shift from chatbots to agents and to using AI for business process automation. By Simon Bisson Nov 20, 2024 7 mins Microsoft Azure Generative AI Development Tools news Microsoft unveils imaging APIs for Windows Copilot Runtime Generative AI-backed APIs will allow developers to build image super resolution, image segmentation, object erase, and OCR capabilities into Windows applications. By Paul Krill Nov 19, 2024 2 mins Generative AI APIs Development Libraries and Frameworks Resources Videos