Introduction
Logging makes applications easy to maintain by giving developers and users the ability to keep track of
their execution. That's why through this article, I wanted to present two different approaches to integrate Logging mechanism into our .NET solutions:
- Implement our own Logging library based on ‘
System.Diagnostics
’ namespace. - Using a third party library called Log4NET: http://logging.apache.org/log4net/
Background
This article may be useful for intermediate developers who have some basics in C#.
Using the Code
Through this article, we will explain in depth logging in .NET applications. We will explain this through two steps:
- Introduction to
System.Diagnostics
(prebuilt logging namespace in .NET) - Introduction to Log4net
I. System.Diagnostics Namespace
The System.Diagnostics
namespace provides classes that allow you to interact with system processes, event logs, and performance counters, Classes like EventLog
which provides functionality to write to event logs, read event log entries, and create and delete event logs and event sources on the network. TraceSource
which also provides a set of methods and properties that enable applications to trace the execution of code and associate trace messages with their source. In this paragraph, we will implement a tracing/Logging library based on the TraceSource
Class. This library enable users to:
- trace different scenarios inside applications [
Start
, Stop
, Error
, Information
, Critical
, Warning
] - The
Trace
destination is configurable, it can be a file, it can be a console application and it supports also sending Log Message by mail.
To do so, this logging utility contains:
- Interface called Logger.cs
- Interface called ILogger.cs
- Enumeration called
LogType
which presents the destination of trace messages
public interface ILogger
{
void TraceStart(string message);
void TraceStop(string message);
void TraceInfo(string message);
void TraceWarning(string message);
void TraceError(string message);
void TraceCritical(string message);
}
public enum LogType
{
File,
Email,
}
The class that implements the interface ILogger.cs:
public class Logger : ILogger
{
#region Members
TraceSource source;
LogType logType;
#endregion
#region Constructor
public Logger(LogType logType)
{
source = new TraceSource("Code Project : ");
this.logType = logType;
}
#endregion
#region Private Methods
void TraceInternal(TraceEventType eventType, string message)
{
if (source != null)
{
try
{
if (this.logType == LogType.File)
{
source.TraceEvent(eventType, (int)eventType, message);
foreach (TraceListener item in source.Listeners)
{
item.IndentSize = 4;
item.Flush();
}
}
else
{
Console.WriteLine("Send Mail");
}
}
catch (SecurityException)
{
}
}
}
#endregion
#region Public Methods
public void TraceStart(string message)
{
TraceInternal(TraceEventType.Start, message);
}
public void TraceStop(string message)
{
TraceInternal(TraceEventType.Stop, message);
}
public void TraceInfo(string message)
{
if (String.IsNullOrEmpty(message))
throw new ArgumentNullException(message);
TraceInternal(TraceEventType.Information, message);
}
public void TraceWarning(string message)
{
if (String.IsNullOrEmpty(message))
throw new ArgumentNullException(message);
TraceInternal(TraceEventType.Warning, message);
}
public void TraceError(string message)
{
if (String.IsNullOrEmpty(message))
throw new ArgumentNullException(message);
TraceInternal(TraceEventType.Error, message);
}
public void TraceCritical(string message)
{
if (String.IsNullOrEmpty(message))
throw new ArgumentNullException(message);
TraceInternal(TraceEventType.Critical, message);
}
#endregion
}
Now let’s see how to configure the library through the configuration file. The configuration file will determine:
- The name of the source
- The type of destination message [a text file, a console file, etc...]
- The trace option output, in our case, the output of any trace containing this message
- The type of trace [information, Error, warning, etc…]
- Date Time of the trace
- Thread ID
- Process ID
- TimeStamp
<system.diagnostics>
<sources>
<source name="CodeProject : " switchName="sourceSwitch"
switchType="System.Diagnostics.SourceSwitch">
<listeners>
<remove name="Default" />
<add name="console" type="System.Diagnostics.ConsoleTraceListener"
traceOutputOptions="DateTime,ThreadId,ProcessId,Timestamp">
<filter type="System.Diagnostics.EventTypeFilter"
initializeData="All"/>
</add>
</listeners>
</source>
</sources>
<switches>
<add name="sourceSwitch" value="All"/>
</switches>
</system.diagnostics>
Testing the library:
Logger Logger = new Logger(LogType.File);
Logger.TraceStart("start Operation");
Logger.TraceInfo("Trace Operation");
Logger.TraceWarning("Warning Operation");
Logger.TraceError("Error Operation");
Logger.TraceCritical("Critical Operation");
Logger.TraceStop("Stop Operation");
If we want to customize the destination of trace messages, for example, display the trace message in a file system, we just add a 'TextWriterTraceListener
' to the configuration file:
<add name="myListener" type="System.Diagnostics.TextWriterTraceListener"
initializeData="E:\TextWriterOutput.log"
traceOutputOptions="DateTime,ThreadId,ProcessId,Timestamp">
<filter type="System.Diagnostics.EventTypeFilter" initializeData="All"/>
</add>
Displaying trace messages in Bloc Notes.
You can customize the tracing output's target by adding or removing TraceListener instances to or from the collection stored in the TraceSource.Listeners property. By default, trace output is produced using an instance of the DefaultTraceListener class. The preceding configuration file example demonstrates removing the DefaultTraceListener
and adding a TextWriterTraceListener
/ConsoleTraceListener
to produce the trace output for the trace source.
As a Microsoft developer, I have always been more comfortable when implementing my own libraries based on .NET prebuilt namespaces because I want to have absolute control on my source code, but I have seen many projects using Logging with third party libraries, for example, Log4Net. In the next paragraph, we will learn how to integrate this library into our applications.
II. Logging with Log4NET
The Apache log4net library is a tool to help the programmer output log statements to a variety of output targets. Log4net is a port of the log4j framework to Microsoft.NET platform. To integrate this library, you must use nuget package manager.
Like the TraceSource
class, Log4net
library enables the developer to customize message tracing (changing the log destinations and the format of messages). We will write two scenarios:
- Default Configuration [Console Configuration]
private static readonly ILog log = LogManager.GetLogger(typeof(Program));
static void Main(string[] args)
{
BasicConfigurator.Configure();
log.Info("Hi ");
log.Warn("Thanks Code Project");
Console.ReadLine();
}
- Using custom configuration [saving messages into a text file].
private static readonly ILog log = LogManager.GetLogger(typeof(Program));
static void Main(string[] args)
{
String configFilePath = AppDomain.CurrentDomain.BaseDirectory + @"\Log4NET.config";
if (File.Exists(configFilePath))
{
XmlConfigurator.Configure(new FileInfo(configFilePath));
log.Info("Hi ");
log.Warn("Thanks Code Project");
}
Console.ReadLine();
}
XML Configuration file
<log4net>
<appender name="FileAppender" type="log4net.Appender.FileAppender">
<file value="E:\log-file.txt" />
<appendToFile value="true" />
<encoding value="utf-8" />
<layout type="log4net.Layout.SimpleLayout" />
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="FileAppender" />
</root>
</log4net>
Displaying trace messages in Bloc Notes.
Summary
Log4net is a port of Log4j to the .NET universe, Log4j is a popular logging framework and that's why log4net has rapidly grown. The class System.Diagnostics.TraceSource
provides high performance logging and tracing for applications but both use nearly the same mechanism.
I hope that you appreciated my effort. Thank you for viewing my blog post, try to download the source code and do not hesitate to leave your questions, comments and thanks if you want to.