Archive

Archive for the ‘Log4Net’ Category

Log4net in VB.NET

A long time ago I wrote this post.
I’m wondering if is still valid, because I was tasked to implement log4net in a .NET framework 4.8 VB.NET Windows Form project with various classes where to implement logging, and there are differences.
First, in every case, we need the NuGet package.
You can use the Visual Studio UI to search for it and install it, or just run this command from the Package Manager Console: PM> Install-Package log4net
Add a new file to your project in Visual Studio called log4net.config and be sure to set a property for the file.
Set Copy to Output Directory to Copy Always.
This is important because we need the log4net.config file to be copied to the bin folder when you build and run your app.
In every class, I needed only to create the variable at the class level, and then in the constructor configure log4net with XmlConfigure; for example:

Imports log4net
Imports log4net.Config

Public Class clsTest
    Private Shared ReadOnly logger As ILog = LogManager.GetLogger(Reflection.MethodBase.GetCurrentMethod().DeclaringType)

    Public Sub New()
        XmlConfigurator.Configure(New System.IO.FileInfo("log4net.config"))
        Try
            Dim i As Int32
            Dim z As Int32 = i / 0
            Debug.Print(z)

        Catch ex As Exception
            logger.Error(ex.Message)
            End
        End Try
    End Sub
End Class  

The task was to dump the errors both in a text file and a SQL Server table.
This is the SQL schema:

CREATE TABLE [dbo].[InternLog](
      [InternLogId] [int] IDENTITY(1,1) NOT NULL,
      [Date] [datetime] NULL,
      [Thread] [varchar](255) NULL,
      [LogLevel] [varchar](50) NULL,
      [Logger] [varchar](255) NULL,
      [Message] [nvarchar](4000) NULL,
      [Exception] [nvarchar](4000) NULL,

 CONSTRAINT [PK_InternLog] PRIMARY KEY CLUSTERED
(
      [InternLogId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

And this is the log4net.config:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
   <configSections>
      <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
   </configSections>
   <log4net>
      <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
         <file value="c:\work\log\amsalert.txt" />
         <appendToFile value="true" />
         <rollingStyle value="Size" />
         <maxSizeRollBackups value="10" />
         <maximumFileSize value="10MB" />
         <staticLogFileName value="true" />
         <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
         </layout>
      </appender>
      <appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
         <bufferSize value="1" />
         <!--Change to 10 or MORE This is critical, it means after 10 messages then the buffer goes to database-->
         <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
         <connectionString value="data source=SERVER;initial catalog=SOMEDB;integrated security=false;persist security info=True;User ID=sa;Password=somepwd" />
         <commandText value="INSERT INTO InternLog ([Date],[Thread],[LogLevel],[Logger],[Message],[Exception]) VALUES (@log_date, @thread, @log_level, @logger, @message, @exception)" />
         <commandType value="Text" />
         <!--<commmandText value="dbo.procLog_Insert"/><commandType value="StoredProcedure"/>-->
         <parameter>
            <parameterName value="@log_date" />
            <dbType value="DateTime" />
            <layout type="log4net.Layout.RawTimeStampLayout" />
         </parameter>
         <parameter>
            <parameterName value="@thread" />
            <dbType value="String" />
            <size value="255" />
            <layout type="log4net.Layout.PatternLayout">
               <conversionPattern value="%thread" />
            </layout>
         </parameter>
         <parameter>
            <parameterName value="@log_level" />
            <dbType value="String" />
            <size value="50" />
            <layout type="log4net.Layout.PatternLayout">
               <conversionPattern value="%level" />
            </layout>
         </parameter>
         <parameter>
            <parameterName value="@logger" />
            <dbType value="String" />
            <size value="255" />
            <layout type="log4net.Layout.PatternLayout">
               <conversionPattern value="%logger" />
            </layout>
         </parameter>
         <parameter>
            <parameterName value="@message" />
            <dbType value="String" />
            <size value="4000" />
            <layout type="log4net.Layout.PatternLayout">
               <conversionPattern value="%message" />
            </layout>
         </parameter>
         <parameter>
            <parameterName value="@exception" />
            <dbType value="String" />
            <size value="2000" />
            <layout type="log4net.Layout.ExceptionLayout" />
         </parameter>
      </appender>
      <root>
         <level value="DEBUG" />
         <appender-ref ref="RollingFileAppender" />
         <appender-ref ref="AdoNetAppender" />
      </root>
   </log4net>
</configuration>
Categories: .NET, Log4Net, SQL Server, VB.NET, Vs2022

Steps for log4net in .NET Framework Console App

In Visual Studio 2017 add from Nuget the Log4Net package.
.
In AssemblyInfo.cs add

[assembly: log4net.Config.XmlConfigurator(Watch = true)]

In the class constructor where you want to use log4net add these lines, this is a skeleton for a Program.cs of a Console app

namespace MyProgram
{
    class Program
    {
        static readonly log4net.ILog logger = log4net.LogManager.GetLogger(typeof(Program));

        static void Main(string[] args)
        {
            log4net.Config.BasicConfigurator.Configure();
        }

Here we can note the typeof(Program), if we have a class named Test we must write typeof(Test), and the code log4net.Config.BasicConfigurator.Configure(); must be in the class constructor.
in app.config for a logging into a text file we must have something as

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
  </configSections>
  <log4net debug="true">
    <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
      <file value="C:\LogWeb\DocValidator-log.txt" />
      <appendToFile value="true" />
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <rollingStyle value="Size" />
      <maxSizeRollBackups value="20" />
      <maximumFileSize value="5MB" />
      <staticLogFileName value="true" />
      <layout type="log4net.Layout.PatternLayout">
        <param name="ConversionPattern" value="%d [%t] %-5p %c [%x] - %m%n" />
      </layout>
    </appender>
    <root>
      <priority value="ALL" />
      <appender-ref ref="RollingFileAppender" />
    </root>
    <category name="my.category">
      <priority value="DEBUG" />
    </category>
  </log4net>

That is if we have a section configSections we must add the new line for log4.net, then add the entire log4net section.
Obvious, he folder must be writable for the IIS user.
If the logging is not working , add the key

<add key="log4net.Internal.Debug" value="true"/>

In the appSettings section of app.config : on the console there will be a very verbose output , that should address an eventual problem.

Categories: .NET, Log4Net, Vs2017