CheapASPNETHostingReview.com | Best and cheap ASP.NET Hosting. 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | /// <summary> /// Trace manager contract for trace instrumentation /// </summary> /// public interface ILogger { /// <summary> /// Send "start" flag to trace repository /// </summary> void TraceStart(string message); /// <summary> /// Send "stop" flag to trace repository /// </summary> void TraceStop(string message); /// <summary> /// Trace information message to trace repository /// <param name="message">Information message to trace</param> /// </summary> void TraceInfo(string message); /// <summary> /// Trace warning message to trace repository /// </summary> /// <param name="message">Warning message to trace</param> void TraceWarning(string message); /// <summary> /// Trace error message to trace repository /// </summary> /// <param name="message">Error message to trace</param> void TraceError(string message); /// <summary> /// Trace critical message to trace repository /// </summary> /// <param name="message">Critical message to trace</param> void TraceCritical(string message); } /// <summary> /// The destination of the trace messages [FileSystem or Emails] /// </summary> public enum LogType { File, Email, } |
The class that implements the interface ILogger.cs:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | public class Logger : ILogger { #region Members TraceSource source; LogType logType; #endregion #region Constructor /// <summary> /// Create a new instance of this trace manager /// </summary> public Logger(LogType logType) { // Create default source source = new TraceSource("Code Project : "); this.logType = logType; } #endregion #region Private Methods /// <summary> /// Trace internal message in configured listeners /// </summary> /// <param name="eventType">Event type to trace</param> /// <param name="message">Message of event</param> 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"); //You just need a function that send Email to someone } } catch (SecurityException) { //Cannot access to file listener or cannot have //privileges to write in event log //do not propagate this :-( } } } #endregion #region Public Methods /// <summary> /// <see cref=" Logging.ILogger"/> /// </summary> public void TraceStart(string message) { TraceInternal(TraceEventType.Start, message); } /// <summary> /// <see cref=" Logging.ILogger"/> /// </summary> public void TraceStop(string message) { TraceInternal(TraceEventType.Stop, message); } /// <summary> /// <see cref=" Logging.ILogger"/> /// </summary> /// <param name="message"><see cref=" Logging.ILogger"/></param> public void TraceInfo(string message) { if (String.IsNullOrEmpty(message)) throw new ArgumentNullException(message); TraceInternal(TraceEventType.Information, message); } /// <summary> /// <see cref=" Logging.ILogger"/> /// </summary> /// <param name="message"><see cref=" Logging.ILogger"/></param> public void TraceWarning(string message) { if (String.IsNullOrEmpty(message)) throw new ArgumentNullException(message); TraceInternal(TraceEventType.Warning, message); } /// <summary> /// <see cref=" Logging.ILogger"/> /// </summary> /// <param name="message"><see cref=" Logging.ILogger"/></param> public void TraceError(string message) { if (String.IsNullOrEmpty(message)) throw new ArgumentNullException(message); TraceInternal(TraceEventType.Error, message); } /// <summary> /// <see cref=" Logging.ILogger"/> /// </summary> /// <param name="message"><see cref=" Logging.ILogger"/></param> 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <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:
1 2 3 4 5 6 7 | Logger Logger = new Logger(LogType.File);//in case when we do not want to send log by Email. 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:
1 2 3 4 5 6 7 8 | <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 aTextWriterTraceListener
/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]
1 2 3 4 5 6 7 8 9 | private static readonly ILog log = LogManager.GetLogger(typeof(Program)); static void Main(string[] args) { // Default Configuration [Console Configuration] BasicConfigurator.Configure(); log.Info("Hi "); log.Warn("Thanks Code Project"); Console.ReadLine(); } |
- Using custom configuration [saving messages into a text file].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | private static readonly ILog log = LogManager.GetLogger(typeof(Program)); static void Main(string[] args) { //The Logging configuration String configFilePath = AppDomain.CurrentDomain.BaseDirectory + @"\Log4NET.config"; if (File.Exists(configFilePath)) { //Load the configuration from the XML File XmlConfigurator.Configure(new FileInfo(configFilePath)); log.Info("Hi "); log.Warn("Thanks Code Project"); } Console.ReadLine(); } |
XML Configuration file
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <log4net> <!--FileAppender --> <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> <!-- On définit le logger root au niveau DEBUG et on l'associe à l'appender A1 --> <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.