Friday, January 11, 2019

Add log4net in .Net Application

log4net library
If you are planning to use the log4net library for error/info/warning logging in your .net project then this post will help you in that. This post will give you the step by step process to setup and use the log4net library. I have used a slightly different approach to consume the basic methods of log4net. Instead of creating a static variable of log4net interface, I created a sealed class and inside that created different methods to log the information. I have used the .net framework 4.5 to take the advantages of CompilerServices. If you don’t know about the CompilerServices refer this link.

Moreover, this article is going to explain you how to log the messages in flat file, database logging and sending the log information via email.

Lets get started
Step 1 – Prerequisite
                Download the latest version of log4net. Or use the neget manager to add the reference.
Step 2 – Add a new class and name it Logger.cs and add the reference of “System.Runtime.CompilerServices”. I will explain about the ThreadContext in later steps.

using System.Runtime.CompilerServices;
using log4net;
using System.Diagnostics;
public sealed class Logger
    {
        public static log4net.ILog  Log { getset; }
        static Logger()
        {
            Log = log4net.LogManager.GetLogger(typeof(Logger));
            //SetLoggerConnectionString();
            ThreadContext.Properties["Priority"] = "0";
            ThreadContext.Properties["Severity"] = "Error";
            ThreadContext.Properties["Title"] = "FileExchange";
            ThreadContext.Properties["MachineName"] = Environment.MachineName;
            ThreadContext.Properties["AppDomainName"] = AppDomain.CurrentDomain.ToString();
            ThreadContext.Properties["ProcessID"] = Process.GetCurrentProcess().Id;
            ThreadContext.Properties["ProcessName"] = Process.GetCurrentProcess().ProcessName;
        }
        public static void Debug(object meg,
            [System.Runtime.CompilerServices.CallerMemberNamestring memberName = "",
            [System.Runtime.CompilerServices.CallerFilePathstring sourceFilePath = "",
            [System.Runtime.CompilerServices.CallerLineNumberint sourceLineNumber = 0)
        {
            Log.Debug(memberName + System.Environment.NewLine +
                        sourceFilePath + System.Environment.NewLine +
                        "Line Number " + sourceLineNumber.ToString() + System.Environment.NewLine +
                        meg);
        }
public static void Warning(object msg,
            [System.Runtime.CompilerServices.CallerMemberNamestring memberName = "",
            [System.Runtime.CompilerServices.CallerFilePathstring sourceFilePath = "",
            [System.Runtime.CompilerServices.CallerLineNumberint sourceLineNumber = 0)
        {
            Log.Warn(memberName + Environment.NewLine +
                        sourceFilePath + Environment.NewLine +
                        "Line Number " + sourceLineNumber.ToString() + Environment.NewLine +
                        msg);
        }

        public static void Error(Exception ex,
            [System.Runtime.CompilerServices.CallerMemberNamestring memberName = "",
            [System.Runtime.CompilerServices.CallerFilePathstring sourceFilePath = "",
            [System.Runtime.CompilerServices.CallerLineNumberint sourceLineNumber = 0)
        {
            Log.Error(memberName + Environment.NewLine +
                        sourceFilePath + Environment.NewLine +
                        "Line Number " + sourceLineNumber.ToString() + Environment.NewLine +
                        ex.Message, ex);
        }

        public static void Info(object msg,
            [System.Runtime.CompilerServices.CallerMemberNamestring memberName = "",
            [System.Runtime.CompilerServices.CallerFilePathstring sourceFilePath = "",
            [System.Runtime.CompilerServices.CallerLineNumberint sourceLineNumber = 0)
        {
            Log.Info(memberName + Environment.NewLine +
                        sourceFilePath + Environment.NewLine +
                        "Line Number " + sourceLineNumber.ToString() + Environment.NewLine +
                        msg);
        }

        public static void Error(object msg,
            [System.Runtime.CompilerServices.CallerMemberNamestring memberName = "",
            [System.Runtime.CompilerServices.CallerFilePathstring sourceFilePath = "",
            [System.Runtime.CompilerServices.CallerLineNumberint sourceLineNumber = 0)
        {
            Log.Info(memberName + Environment.NewLine +
                        sourceFilePath + Environment.NewLine +
                        "Line Number " + sourceLineNumber.ToString() + Environment.NewLine +
                        msg);
        }

        public static void Fatal(object msg,
            [System.Runtime.CompilerServices.CallerMemberNamestring memberName = "",
            [System.Runtime.CompilerServices.CallerFilePathstring sourceFilePath = "",
            [System.Runtime.CompilerServices.CallerLineNumberint sourceLineNumber = 0)
        {
            Log.Fatal(memberName + Environment.NewLine +
                        sourceFilePath + Environment.NewLine +
                        "Line Number " + sourceLineNumber.ToString() + Environment.NewLine +
                        msg);
        }
    }

Step 3 – Configuration setting for log4net
                Common Settings
                                If you are adding the config changes in your app.config or web.config then you need to add the below setting
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
  </configSections>
  <log4net>
    <root>
      <level value="ALL" />
      <appender-ref ref="LogFileAppender" />
      <appender-ref ref="ADONetAppender" />
      <appender-ref ref="RollingFileAppender" />
      <appender-ref ref="SmtpAppender" />
    </root>
  </log4net>

Step 4 – Add below configuration under the root element

       LogFileAppender Configuration
    <appender name="LogFileAppender" type="log4net.Appender.FileAppender,log4net">
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <file value="./Log/TestConsole.log" />
      <appendToFile value="true" />
      <layout type="log4net.Layout.PatternLayout, log4net">
        <param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n" />
      </layout>
    </appender>

ADONetAppender Configuration
You need to specify the connection string under connectionStrings section
<appender name="ADONetAppender" type="log4net.Appender.AdoNetAppender">
      <bufferSize value="1" />
      <connectionStringName value="DBConnection" />
      <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
      <commandText value="INSERT INTO LogTable ([Priority],[Severity],[Title],[Timestamp],[MachineName],[AppDomainName],[ProcessID],[ProcessName],[Message]) VALUES (@Priority, @Severity, @Title, @Timestamp, @MachineName,@AppDomainName,@ProcessID,@ProcessName, @Message)" />
      <parameter>
        <parameterName value="@Priority" />
        <dbType value="String" />
        <size value="32" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%property{Priority}" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@Severity" />
        <dbType value="String" />
        <size value="32" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%property{Severity}" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@Title" />
        <dbType value="String" />
        <size value="156" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%property{Title}" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@Timestamp" />
        <dbType value="DateTime" />
        <layout type="log4net.Layout.RawTimeStampLayout" />
      </parameter>
      <parameter>
        <parameterName value="@MachineName" />
        <dbType value="String" />
        <size value="32" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%property{MachineName}" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@AppDomainName" />
        <dbType value="String" />
        <size value="512" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%property{AppDomainName}" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@ProcessID" />
        <dbType value="String" />
        <size value="256" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%property{ProcessID}" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@ProcessName" />
        <dbType value="String" />
        <size value="512" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%property{ProcessName}" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@Message" />
        <dbType value="String" />
        <size value="1500" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%message" />
        </layout>
      </parameter>
      <filter type="log4net.Filter.LevelRangeFilter">
        <levelMin value="WARN" />
        <levelMax value="ERROR" />
      </filter>
    </appender>
RollingFileAppender Configuration
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
      <file value="./Log/TestConsole.log" />
      <appendToFile value="true" />
      <rollingStyle value="Size" />
      <maxSizeRollBackups value="15" />
      <maximumFileSize value="10MB" />
      <staticLogFileName value="true" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %level %logger - %message%newline" />
      </layout>
    </appender>
SmtpAppender Configuration
    <appender name="SmtpAppender" type="log4net.Appender.SmtpAppender,log4net">
      <to value="xyz@xyz.com" />
      <from value=" xyz@xyz.com" />
      <subject value="test logging message" />
      <smtpHost value="SMTP host name" />
      <bufferSize value="512" />
      <lossy value="false" />
      <evaluator type="log4net.Core.LevelEvaluator,log4net">
        <threshold value="WARN" />
      </evaluator>
      <layout type="log4net.Layout.PatternLayout,log4net">
        <conversionPattern value="%property{log4net:HostName} :: %level :: %message %newlineLogger: %logger%newlineThread: %thread%newlineDate: %date%newlineNDC: %property{NDC}%newline%newline" />
      </layout>

Step 5 – for database logging, if your table structure is different than the default log4net table structure then you need to do extra coding.
                Default log4net table structure
       [Date], [Thread], [Level], [Logger], [Message], [Exception]
In this example, I have used the custom table and it might be different in your case. The point that I am trying to make here is that you need to add the other column value ThreadContext (YOU CAN FIND THE CODE IN THE CONSTRUCTOR (Step 1))
[Priority], [Severity], [Title], [Timestamp], [MachineName], [AppDomainName], [ProcessID], [ProcessName], [Message]
Step 6 - AssemblyInfo.cs file changes
                You need to add below link of code in AssemblyInfo.cs file to tell the log4net where to find the configuration.
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
Step 7 – If you are on this step then you have completed the 99% of work and now you need to use the logger class in your code to log the messages. Simple example would be
try
            {
//Do something
     }

            catch (Exception ex)
            {
                Logger.Debug(ex);
            }

No comments: