Log4net not working in multithreading in C# - c#

hello friends i have added log4net package form nuget packages. for sync call log4net add logs in log file but when i am declaring a methods using Task its not working
<log4net>
<appender name="TestAppender" type="log4net.Appender.RollingFileAppender">
<file value="D:\log\logswebapi.log" />
<encoding value="utf-8" />
<appendToFile value="true" />
<rollingStyle value="Date" />
<layout type="log4net.Layout.PatternLayout">
<!--<conversionPattern value="%date %level [%thread] %type.%method - %message%n" />-->
</layout>
</appender>
<root>
<level value="All" />
<!-- If the following line is not included the log file
will not be created even if log4net is configured with this file. -->
<appender-ref ref="TestAppender" />
</root>
</log4net>
i have added this code in web.config file
private void AddLog(string str)
{
ILog Log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
Log.Info(DateTime.Now + " - " + str);
}
public string SendDocument(){
// send document logic
AddLog(send document done");
}
public string Response(){
Task.Run(() =>SendDocument()); // here i am calling this senddocument method in thread
}
in above code Response method i am calling send document methods in thread but logs are not added now how to resolve this issue ?
thanks in advance

Related

How to configure logging via log4net in an UWP App

I have an UWP app that uses some of my libraries.
Such libraries use log4net for logging purpose, and are shared across a number of projects, not only UWP.
I'd like to configure log4net via the usual confi section in the XML config file, but I cannot find a way to do this in an UWP project, since there isn't an app.config file.
Where should I put the following section?
<log4net>
<appender name="Console" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date - %message%newline" />
</layout>
</appender>
<appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
<file value="log\mylog.log" />
<appendToFile value="true" />
<maximumFileSize value="2000KB" />
<maxSizeRollBackups value="20" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date - %message%newline" />
</layout>
</appender>
<root>
<level value="INFO" />
<appender-ref ref="Console" />
<appender-ref ref="RollingFile" />
</root>
</log4net>
Thank you!
To complete pfx answer, if you are using netStandard, you will have to use Configure overloads with an additional parameter log4net.Repository.ILoggerRepository.
I haven't been able to use the ConsoleAppender and switch to the DebugAppender.
You cannot use relative path in UWP with RollingFileAppender since log4net will not have permission to create file in the install location of your application. I think it could work with a full path but I have seen some permissions issues (you should activate debug mode of log4net for this).
Finally, I also made a Custom Appender which writes file in the Local Storage of your application. Here is the code which should be enhanced for production use.
namespace AppWithLog4net
{
public class LocalStorageFileAppender : log4net.Appender.TextWriterAppender
{
private Stream m_stream;
public LocalStorageFileAppender() : base() { }
protected override void PrepareWriter()
{
IAsyncOperation<Windows.Storage.StorageFile> task = Windows.Storage.ApplicationData.Current.LocalCacheFolder.CreateFileAsync("localStorage.log",
Windows.Storage.CreationCollisionOption.GenerateUniqueName);
Windows.Storage.StorageFile file = task.GetAwaiter().GetResult();
m_stream = file.OpenStreamForWriteAsync().Result;
QuietWriter = new log4net.Util.QuietTextWriter(new StreamWriter(m_stream, Encoding.UTF8), ErrorHandler);
WriteHeader();
}
protected override void Reset()
{
m_stream.Dispose();
m_stream = null;
base.Reset();
}
}
}
With the following config file:
<log4net debug="true">
<appender name="Console" type="log4net.Appender.DebugAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date - %message%newline" />
</layout>
</appender>
<appender name="LocalStorageFile" type="AppWithLog4net.LocalStorageFileAppender, AppWithLog4net">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date - %message%newline" />
</layout>
</appender>
<root>
<level value="INFO" />
<appender-ref ref="Console" />
<appender-ref ref="LocalStorageFile" />
</root>
</log4net>
Because there is no App.config file, you are going to have to configure Log4net programmatically.
You can store the settings in a local file (or embedded resource) and read these at application startup; reference: Create and read a local file.
Log4net's XmlConfigurator class can accept these settings as a Stream, FileInfo or XmlElement via one of its Configure overloads.
log4net.Config.XmlConfigurator.Configure(XmlElement config);
log4net.Config.XmlConfigurator.Configure(Stream config);
log4net.Config.XmlConfigurator.Configure(FileInfo config);

Log4net not logging on Azure Webapp

For a web service, I have log4net configured and working fine locally but not when the webapp is deployed on Azure Webapp. The directory is created but there is nothing logged at the file..
Here is my config:
<log4net>
<appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
<file value="log/sms.log" />
<appendToFile value="true" />
<maximumFileSize value="10MB" />
<maxSizeRollBackups value="10" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %level - %message%newline" />
</layout>
</appender>
<logger name="TheLogger">
<appender-ref ref="RollingFile" />
</logger>
Within my AssemblyInfo.cs I have:
[assembly: XmlConfigurator(Watch = true)]
At the Startup class i have :
public static ILog Logger { get; private set; }
public void Configuration(IAppBuilder appBuilder)
{
Logger = LogManager.GetLogger("TheLogger");
Logger.Info("Application start...");
}
Clearly my configuration is being picked up because in my log file is written the hour/date format and also Application start... but not the logging information.
What am i missing?
Make sure you don't forget to add the root configuration.
Are compiling for Debug and deploying in Azure in Release mode?
<log4net>
<root>
<level value="INFO" />
<appender-ref ref="RollingFile" />
</root>
<appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
<!-- ... -->
</appender>
</log4net>
I had the same problem and found a solution. I had to replace these 2 lines of code in the Program class of the .Net Core API:
XmlDocument log4netConfig = new XmlDocument();
log4netConfig.Load(File.OpenRead("log4net.config"));
With this:
var logRepository = LogManager.GetRepository(Assembly.GetEntryAssembly());
XmlConfigurator.Configure(logRepository, new FileInfo("log4net.config"));
The reason is because in .Net Framework API's I used the assembly attribute to set this, now I need to do it like this.

log4net multiple loggers - properties

log4net v. 2.0.8
I've got some problems in multiple logging with log4net. I'm developing an application that works with n devices and I would like to have a single log file for each device.
log4net.config
<log4net>
<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
<file type="log4net.Util.PatternString" value="%envFolderPath{LocalApplicationData}/Foo/Device%property{DeviceID}/log.txt"/>
<appendToFile value="true"/>
<maxSizeRollBackups value="10"/>
<maximumFileSize value="10MB"/>
<layout type="log4net.Layout.PatternLayout">
<param name="Header" value="BEGIN LOGGING AT %date *** %property *** %newline" type="log4net.Util.PatternString" />
<param name="Footer" value="END LOGGING AT %date *** %property *** %newline" type="log4net.Util.PatternString" />
<param name="ConversionPattern" value="%date [%thread] %-5level %-5class{1} %-5method(%line) %message %newline" />
</layout>
<filter type="log4net.Filter.PropertyFilter">
<key value="Version" />
<stringToMatch value="1" />
</filter>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="LogFileAppender" />
</root>
and this is the code
public DeviceClass(string deviceID)
{
InitializeComponent();
GlobalContext.Properties["DeviceID"] = deviceID;
logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
logger.Debug("Hello world");
The problem is that if I have for example two devices I got just the first log file with the messages from all devices.
I'm not a Log4Net expert, but I believe that the log manager is going to initialize the logger and all of its appenders the first time that you call GetLogger for the given type/name (type under covers is translated to a string name). That being the case, it wouldn't re-initialize one per device. My suggestion for you is to try creating a composite of the type name and device ID using something like:
logger = LogManager.GetLogger($"{System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName}{deviceId}");

Configure Log4Net for the full project

I have the following code which Logs everything very nicely. Am I going to have to add this to the constructor of all of my classes?
Is there anyway to configure it for the full project? I suppose I could pass log around to all of the classes but that seams like a messy solution.
class Program
{
/// <summary>
/// Application start
/// <param name="settings"></param>
/// <returns></returns>
static int Main(string[] args)
{
string logFile = string.Format(#"{0}\Cloud\Cloud.Log", Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData));
log4net.GlobalContext.Properties["LogFileName"] = logFile;
log4net.Config.XmlConfigurator.Configure();
ILog log = log4net.LogManager.GetLogger(typeof(Program));
log.Info("Console Applicatin Start");
}
}
How should can I configure Log4Net for the full solution?
I didn't think it was relevant to the question but here is my my App.config:
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file type="log4net.Util.PatternString" value="%property{LogFileName}.txt" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="250KB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="RollingFileAppender" />
</root>
</log4net>
I usually use a wrapper class. Something like:
public class Logger
{
private static readonly log4net.ILog _log = log4net.LogManager.GetLogger(typeof(Logger));
static Logger()
{
log4net.Config.XmlConfigurator.Configure();
}
public void Error(string format, params object[] args)
{
_log.Error(string.Format(format, args));
}
//...
}
And then just instantiate that where I need it. Like:
private Logger _log = new Logger();
And the use it like:
_log.Error("Something went wrong, Exception: {0}, More parameters: {1}",
e.Message, "Another parameter");
The
log4net.Config.XmlConfigurator.Configure();
Should configure log4net according to your app.config.
Edit:
I thought I'd post my log4net config, in case you want to try one that has been confirmed working. It sets up a file logger and a console logger (useful to see logging i development environment):
<log4net>
<root>
<level value="ALL" />
<appender-ref ref="ConsoleAppender" />
<appender-ref ref="DebugFileLogger" />
</root>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger: %message%newline" />
</layout>
</appender>
<appender name="DebugFileLogger" type="log4net.Appender.RollingFileAppender">
<param name="File" value="Logs/DebugLog.log" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="20MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d%t %m%n" />
</layout>
</appender>
</log4net>
One of the great features of log4net is the ability to configure filtering and processing differently depending on the logger name: any solution that wraps the logger in a wrapper, singleton or static object loses that as all logs will use the same logger name - and the useful ability to immediately see what class a log entry came from.
All you need in a class where you want to log is a field, eg:
private static ILog Log =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
which sets the logger name to the name of the type it's contained in.
The solution I see most often, is to create a LogManager class, and a property in each class to fetch an instance of a logger, so this is the only lines of code needed in each class to get a logger:
private ILog _log;
public ILog Log
{
get { return _log ?? (_log = LogManager.GetLogger(LogName.WebServices)); }
}
The LogName.WebServices is an Enum value, and should be extended with more values, so you are able to filter your logs even more.

log4net BasicConfigurator is not printing on console

I decided to use log4net to handle all the logging activities for the application I am working on... after reading through documentation, I decided to start making experiments, but failed miserably at the very first attempt
The application is being developed with c# using MonoDevelop 3.0.3.2 in a fairly standard Debian 7 distribution, in order to later be deployed on Linux machines.
The code is trivial so far and follows the very early steps in the log4net documentation, and is quoted at the end of the post.
The problem is that the logger does not print anything to console; while trying to understand what's going wrong, I looked intoo it with the debugger; I see that the log reference contains the AppendersCollection, which unfortunately is empty I guess that something is not working properly during configuration and I have no appenders, hence there is no log output.
What am I missing? any suggestion? Is there some sort of a known issue for the combination of MonoDevelop-Linux-log4net I am not aware of?
using System;
using log4net;
using log4net.Config;
namespace TestLog4Net
{
class MainClass
{
private static readonly ILog log = LogManager.GetLogger(typeof(MainClass));
public static void Main (string[] args)
{
BasicConfigurator.Configure();
Console.WriteLine ("Hello World!");
log.Info("Hello World!");
}
}
}
UPDATE
I did some tests loading the configuration file.
I created 3 loggers each with its own appender, two are rolling file appenders, and one is the console appender.
Then I log "Hello World!" on each logger.
The rolling file loggers work as expected, while the output from the ConsoleLogger is nowhere to be found. I checked with the Debugger and the clogger object does NOT display an empty AppenderCollection, but there no output anyway. Below you can find the updated code along with the configuration file.
using System;
using log4net;
using log4net.Config;
namespace TestLog4Net
{
class MainClass
{
public static void Main (string[] args)
{
XmlConfigurator.Configure(new System.IO.FileInfo("app.config"));
ILog rflogger1 = LogManager.GetLogger("RFLoggerOne");
ILog rflogger2 = LogManager.GetLogger("RFLoggerTwo");
ILog clogger = LogManager.GetLogger("CLogger");
rflogger1.Info("Hello World!");
rflogger2.Info("Hello World!");
clogger.Info("Hello World!");
Console.WriteLine ("Hello World!");
}
}
}
<log4net>
<appender name="CAppender" type="log4net.Appender.AnsiColorTerminalAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
</appender>
<appender name="RFAppender1" type="log4net.Appender.RollingFileAppender">
<file value="rf1.log"/>
<appendToFile value="true"/>
<rollingStyle value="Composite"/>
<datePattern value="yyyyMMdd"/>
<maxSizeRollBackups value="10"/>
<maximumFileSize value="1000000"/>
<staticLogFileName value="true"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %level %logger - %message%newline"/>
</layout>
</appender>
<appender name="RFAppender2" type="log4net.Appender.RollingFileAppender">
<file value="rf2.log" />
<appendToFile value="true" />
<maximumFileSize value="100KB" />
<maxSizeRollBackups value="2" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%level %thread %logger - %message%newline" />
</layout>
</appender>
<logger name="CLogger">
<level value="ALL"/>
<appender-ref ref="CAppender"/>
</logger>
<logger name="RFLoggerOne">
<level value="ALL"/>
<appender-ref ref="RFAppender1"/>
</logger>
<logger name="RFLoggerTwo">
<level value="ALL"/>
<appender-ref ref="RFAppender2"/>
</logger>
<root>
<level value="ALL"/>
</root>
</log4net>
Which kind of project do you use? A Console Application?
There are several cases you wont see any output on std::out or std::err on your console.
Have a look at this post:
Can one executable be both a console and GUI application?

Categories