Click here to Skip to main content
15,868,016 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
We are using log4net in our application. The real problem is the log messages not properly logged in Asynchronous method.

We have two applications First one is Console Application and another one is a .Net Web API.

We use Asynchronous logic in Console application. We are calling API service in that Console application through Asynchronous method. Log4net implemented in that API application also.

We have logged all the requests in that API service, but sometimes the log was not properly logged or skipped in the log file.

Ex: The Console application calling 1000 times in that API service. But the API service not writing all the requests, skipped 10 or 20 requests.

I have provided my API sample Code.

Any one please do the help.

C#
Program.cs
------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using log4net;
using System.Reflection;

namespace Log4NetAsynchronous
{
    class Program
    {
        public static async Task<int> Method1(int i)
        {
            return await Task.Run(() =>
            {
                Console.WriteLine("Method 1 ==> " + i.ToString() + "\n");
                Logger.LogMsg("Method 1 -> Line Number: " + i.ToString() + Environment.NewLine, Enums.Methods.Method1, Enums.LogType.INFO);
                Logger.LogMsg("Method 1 -> Line Number: " + i.ToString() + Environment.NewLine, Enums.Methods.Method1, Enums.LogType.DEBUG);
                Logger.LogMsg("Method 1 -> Line Number: " + i.ToString() + Environment.NewLine, Enums.Methods.Method1, Enums.LogType.ERROR);
                Task.Delay(1500).Wait();
                return 1;
            });
        }

        public static async Task<int> Method2(int i)
        {
            return await Task.Run(() =>
            {

                Console.WriteLine("Method 2 ==> " + i.ToString() + "\n");
                Logger.LogMsg("Method 2 -> Line Number: " + i.ToString() + Environment.NewLine, Enums.Methods.Method2, Enums.LogType.INFO);
                Logger.LogMsg("Method 2 -> Line Number: " + i.ToString() + Environment.NewLine, Enums.Methods.Method2, Enums.LogType.DEBUG);
                Logger.LogMsg("Method 2 -> Line Number: " + i.ToString() + Environment.NewLine, Enums.Methods.Method2, Enums.LogType.ERROR);
                Task.Delay(1500).Wait();
                return 1;
            });
        }

        public static async Task<int> Method3(int i)
        {
            return await Task.Run(() =>
            {

                Console.WriteLine("Method 3 ==> " + i.ToString() + "\n");
                Logger.LogMsg("Method 3 -> Line Number: " + i.ToString() + Environment.NewLine, Enums.Methods.Method3, Enums.LogType.INFO);
                Logger.LogMsg("Method 3 -> Line Number: " + i.ToString() + Environment.NewLine, Enums.Methods.Method3, Enums.LogType.DEBUG);
                Logger.LogMsg("Method 3 -> Line Number: " + i.ToString() + Environment.NewLine, Enums.Methods.Method3, Enums.LogType.ERROR);
                Task.Delay(1500).Wait();
                return 1;
            });
        }

        public static async Task<IEnumerable<int>> Invoke1()
        {
            var method1 = new List<Task<int>>();
            for (int i = 1; i <= 3; i++)
            {
                method1.Add(Method1(i));
            }

            return await Task.WhenAll(method1);
        
        }
        public static async Task<IEnumerable<int>> Invoke2()
        {
            var method2 = new List<Task<int>>();
            for (int i = 1; i <= 5; i++)
            {
                method2.Add(Method2(i));
            }

            return await Task.WhenAll(method2);
        }
        public static async Task<IEnumerable<int>> Invoke3()
        {
            var method3 = new List<Task<int>>();
            for (int i = 1; i <= 5; i++)
            {
                method3.Add(Method3(i));
            }

            return await Task.WhenAll(method3);
        }

        static void Main(string[] args)
        {
            Console.WriteLine("Start");
            var res1 = Invoke1();
            var res2 = Invoke2();
            var res3 = Invoke3();
            Console.WriteLine("Succes");
            Console.ReadKey();
        } 
    }
}
--------------

Logger.cs
--------------
using log4net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Log4NetAsynchronous
{
    public static class Logger
    {
        private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

        public static void LogMsg(string msg, Enums.Methods Methods, Enums.LogType logType)
        {
            string strLogFileName = String.Empty;
            switch (Methods)
            {
                case Enums.Methods.Method1:
                    strLogFileName = "Method1";
                    break;

                case Enums.Methods.Method2:
                    strLogFileName = "Method2";
                    break;

                case Enums.Methods.Method3:
                    strLogFileName = "Method3";
                    break;
                default:
                    strLogFileName = "Method1";
                    break;
            }

            log4net.GlobalContext.Properties["LogFileName"] = strLogFileName;
            log4net.Config.XmlConfigurator.Configure();

            ILog log = LogManager.GetLogger(typeof(Logger));

            string timeStamp = string.Empty;

            switch (logType)
            {
                case Enums.LogType.DEBUG:
                    log.Debug(msg);
                    break;

                case Enums.LogType.INFO:
                    log.Info(msg);
                    break;

                case Enums.LogType.ERROR:
                    log.Error(msg);
                    break;
               default:
                    log.Info(msg);
                    break;
            }
        }
    }
}
-----------------

Enums.cs
-----------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Log4NetAsynchronous
{
    public class Enums
    {
        public enum Methods : int
        {
            Method1 = 1,

            Method2 = 2,

            Method3 = 3,
        }

        public enum LogType : int
        {
            DEBUG = 0,

            INFO = 1,

            WARN = 2,

            ERROR = 3,

            FATAL = 4,

            LOGDBINFO = 5,

            LOGSERVICEINFO = 6
        }

    }
}


HTML
<pre>App.config
--------------------
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <!--log4net config section registration-->
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
  </configSections>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>

  <!--log4net  config (configurations) section-->
  <log4net>
    <root>
      <level value="DEBUG" />
      <appender-ref ref="InfoLogAppender" />
      <appender-ref ref="DebugLogAppender" />
      <appender-ref ref="ErrorLogAppender" />
    </root>
    <appender name="InfoLogAppender" type="Log4NetAsynchronous.AsynchronousFileAppender">
      <file type="log4net.Util.PatternString" value="D:\\Logs\\InfoLog\\%property{LogFileName}\\" />
      <datePattern value="dd-MMM-yyyy'.log'" />
      <appendToFile value="true" />
      <rollingStyle value="Composite" />
      <maximumFileSize value="10MB" />
      <param name="StaticLogFileName" value="false"/>
      <threshold value="INFO" />
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date{dd/MMM/yyyy hh:mm:ss} [%level] - %message" />
      </layout>
      <filter type="log4net.Filter.LevelRangeFilter">
        <levelMin value="INFO" />
        <levelMax value="INFO" />
      </filter>
      <filter type="log4net.Filter.DenyAllFilter"/>
    </appender>

    <appender name="DebugLogAppender" type="Log4NetAsynchronous.AsynchronousFileAppender">
      <file type="log4net.Util.PatternString" value="D:\\Logs\\DebugLog\\%property{LogFileName}\\" />
      <datePattern value="dd-MMM-yyyy'.log'" />
      <appendToFile value="true" />
      <rollingStyle value="Composite" />
      <threshold value="DEBUG" />
      <maximumFileSize value="10MB" />
      <param name="StaticLogFileName" value="false"/>
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date{dd/MMM/yyyy hh:mm:ss} [%level] - %message" />
      </layout>
      <filter type="log4net.Filter.LevelRangeFilter">
        <levelMin value="DEBUG" />
        <levelMax value="DEBUG" />
      </filter>
      <filter type="log4net.Filter.DenyAllFilter"/>
    </appender>

    <appender name="ErrorLogAppender" type="Log4NetAsynchronous.AsynchronousFileAppender">
      <file type="log4net.Util.PatternString" value="D:\\Logs\\ErrorLog\\%property{LogFileName}\\" />
      <datePattern value="dd-MMM-yyyy'.log'" />
      <appendToFile value="true" />
      <rollingStyle value="Composite" />
      <threshold value="ERROR" />
      <maximumFileSize value="10MB" />
      <param name="StaticLogFileName" value="false"/>
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date{dd/MMM/yyyy hh:mm:ss} [%level] - %message" />
      </layout>
      <filter type="log4net.Filter.LevelRangeFilter">
        <levelMin value="ERROR" />
        <levelMax value="ERROR" />
      </filter>
      <filter type="log4net.Filter.DenyAllFilter"/>
    </appender>
  </log4net>  

</configuration>



What I have tried:

Actually the same logic only we have implemented in our API.

This code also getting the same issue whatever I'm getting in our API application.

Thanks,

Rajesh
Posted
Updated 30-Jun-20 22:55pm
v2

1 solution

iirc, Log4Net IS a synchronous logger, at least out of the box. There are some examples on the website of creating an asynch logger - I'll provide some urls that may be of use

Using asynchronous log4net appenders for high performance logging[^]

c# - How do I create an asynchronous wrapper for log4net? - Stack Overflow[^]

this link alludes to the existence of Log4Net.Async Testing Log4Net.Async with statsd and Graphite ~ andyfrench.info[^] - see also NuGet Gallery | Log4Net.Async 2.0.4[^] ... Chris Haines who wrote this is also in the SO Thread (the 2nd link)
 
Share this answer
 
Comments
K.B.Rajesh 30-Jun-20 7:46am    
Thanks you so much for your response.
I have changed the code ThreadPool.QueueUserWorkItem(task => log.Debug(msg)) instead of log.Error(msg) in Logger file.

Now, All logs are writing properly. but I'm facing another one problem. All Info, Debug, & errors writing in same file.

Please help on this. I need to write seperate file for all level.
Garth J Lancaster 30-Jun-20 9:58am    
ok, that's a 'different' requirement ... what you need to do is set up an appender for each level -> log file
So, for each level, create a new appender (file, rolling file, whatever) - using 'info' as an example ..
1) name it eg RFAppender-info
2) set the file value to a unique file path/file-info
3) set the filter type to "log4net.Filter.LevelRangeFilter"
4) set the filter levelMin & levelMax to "INFO"
5) add the appender to the 'root' list of appenders
Im sure if you google for 'log4net different file per level' you will find the information if this doesnt make sense
Garth J Lancaster 30-Jun-20 10:01am    
btw - log4net file appenders have a setting iirc that allows you to set the locking mode of the file - see this https://logging.apache.org/log4net/release/sdk/html/P_log4net_Appender_FileAppender_LockingModel.htm ... you should probably set yours to MinimalLock
K.B.Rajesh 2-Jul-20 0:09am    
Garth J Lancaster, Thank you so much for your support..!

But I want to make to store the logs in below folder structure.

Root Folder:
-----------------
Logs-
----InfoLog-
--------Method1
--------Method2
--------Method3
----DebugLog-
--------Method1
--------Method2
--------Method3
----ErrorLog-
--------Method1
--------Method2
--------Method3

I want to store each Method Info, Debug & and Error logs to specific each folder structure.

If don't mind, could you please provide the sample code.
Garth J Lancaster 2-Jul-20 0:58am    
tl/dr; short answer 'no, not sorry'
long answer - apart from that I disagree with what you're doing to your logs, the information is out there on the net on how to split logs how you asked (excluding the 'Method1' example, which is likely formatting the log strings) is out there on the net .. you're probably being paid to do this work - I am currently unemployed, so at some stage you should do your own research/leg-work

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900