Log4net - How to get calling method name when using wrapper - c#

I have a log4net wrapper for logging error messages in web api application. It is working fine but i am not able to log calling method name. It only display's top level method name. Lets say, i have a method a of class A which calls method b of a class B and b logs error message. Log4net only displays Class A and method a but i want to display either full calling chain A-a-B-b or at least B-b
private static readonly ILog LoggerObject = LogManager.GetLogger("ErrorLog");
log4net config
<log4net>
<appender name="ErrorLog" type="log4net.Appender.RollingFileAppender">
<file value="LogBackUp2.log" />
<staticLogFileName value="false" />
<appendToFile value="true" />
<rollingStyle value="Date" />
<datePattern value="yyyy-MM-dd.'Err'" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%M %C] - %message%newline" />
</layout>
</appender>
<logger name="ErrorLog">
<maximumFileSize value="15MB" />
<appender-ref ref="ErrorLog" />
</logger>
</log4net>
If i use this then log4net doesn't create any log file.
LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType)

use %stacktrace{5} to show 5 levels of the stacktrace which lead to the call of the log method. Replace the 5 with the level you want to have. example:
<conversionPattern value="%date [%thread] %-5level %logger [%stacktrace{5}] - %message%newline" />
When you use a log4net wrapper you may want to apply this to get rid of the wrapper in the stacktrace

Related

How to log timestamp in EST format using log4net configuration ignoring the Server Timezone it runs on

I have added my log4net.config setting at the end of my question.
In "MyLog.txt" file I want to log timestamp in EST format using just the config file.
It should replace the %date in config below. I have seen some random articles suggest something like %d{yyyy-MM-dd HH:mm:ss}{GMT-4} but that didnt work.
I also read that Log4j has something called EnhancedPatternLayout which seems to have such date options. But Log4net has nothing equivalent.
Please share if you have some solution to show EST dynamically in Log irrespective of the Server timezone it runs on.
<appender name="ApiLoggerAppender" type="log4net.Appender.RollingFileAppender">
<lockingModel type="log4net.Appender.FileAppender+MinimalLock"/>
<file value="C:\MyLog.txt"/>
<appendToFile value="true" />
<rollingStyle value="Date" />
<datePattern value="-ddMMyyyy" />
<PreserveLogFileNameExtension value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %level %logger - %message%newline" />
</layout>
</appender>

Configuring log4net without code in Rider for dotnet 2.1 project

I'm working on a pet .netcore2.1 project using Rider IDE. I'm currently trying to add log4net support for the project, and trying to do it the "proper way" (separate config file, automatically configure log4net without having to write code for intialization etc.). So far all tutorials (ex1, ex2) I've found suggest configuring it by adding assembly property
[assembly: log4net.Config.XmlConfigurator(Watch=true)]
to AssemblyInfo.cs file. However I seem to fail to find the file, and it looks from other questions (e.g. this) that it might not be used with .netcore at all, in favor of doing configuration via other means (e.g. .csproj file).
So far I've found a workaround here, which works, but it uses explicit configuration via code, which looks like a step backwards compared to assembly-level configuration.
Is there a way of doing this in a more static way (e.g. using some ItemGroup in .csproj)?
Upd: for future reference - this is just a custom case of https://learn.microsoft.com/en-us/dotnet/standard/assembly/set-attributes , so it just goes to .cs file directly.
Easy example using log4net for .net core in console:
[assembly: XmlConfigurator(Watch = true)]
namespace ConsoleApp
{
class Program
{
private static readonly ILog log = LogManager.GetLogger(typeof(Program));
static void Main(string[] args)
{
var logRepository = LogManager.GetRepository(Assembly.GetEntryAssembly());
XmlConfigurator.Configure(logRepository, new FileInfo("log4net.config"));
log.Info("Entering application.");
log.Error("Error application.");
}
}
}
You need to add file with settings log4net to your project: log4net.config, and don't forget chnage it options "Copy to output directory" to "Copy if newer" or "Copy always"
Example of log4net.config:
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender" >
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%ndc] - %message%newline" />
</layout>
</appender>
<appender name="FileAppender" type="log4net.Appender.RollingFileAppender">
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<file value="logs/" />
<datePattern value="yyyy-MM-dd'.log'" />
<staticLogFileName value="false" />
<appendToFile value="true" />
<rollingStyle value="Composite" />
<layout type="log4net.Layout.PatternLayout">
<IgnoresException value="False" />
<conversionPattern value="%date [%thread] %-5level %logger [%ndc] - %message%newline" />
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="INFO"/>
</filter>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="FileAppender" />
<appender-ref ref="ConsoleAppender" />
</root>
</log4net>
By the way: log4net don't supporting for 1 april 2020: http://logging.apache.org/log4net/

Log4Net RollingFileAppender losing messages

I am using log4net to log to files and for some reason, some log messages are lost, and always in the same spot. First my configuration:
<log4net>
<root>
<level value="ALL" />
<appender-ref ref="RollingFileAppender" />
</root>
<appender name="aiAppender" type="Microsoft.ApplicationInsights.Log4NetAppender.ApplicationInsightsAppender, Microsoft.ApplicationInsights.Log4NetAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message%newline" />
</layout>
</appender>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="logs\import.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 [%property{NDC}] - %message%newline" />
</layout>
</appender>
</log4net>
The aiAppender, while defined, is not used.
The log pattern is that I initially burst log about 88 lines of which all are there. Then the missing log period starts and lasts approx 6 seconds. Then the logging continues and everything is logged from that point onward.
If I remove the burst logging and replace it with only a few log entries, nothing is lost.
Apparently RollingFileAppender can lose messages. I wasn't aware of that.
I am certain this is an issue with log4net, as I have a log-wrapper where I split my log messages to both log4net and to application insights (the aiAppender didn't do a good enough job for us) and application insights does receive the messages that log4net doesn't log.
Can I configure the RollingFileAppender to avoid losing messages?
Edit: The log wrapper logs first to log4net and then to application insights so it is not a question about the application insights logging that prevents log4net logging.
You can only debug this when you activate internal debugging. Active the debugger and see if for example log4net is reconfigured at some point.

MemoryAppender.GetEvents : Events Null

can anyone explain why I am not getting any events from the memoryAppender?
In other words, the events variable is Null.
public void Log(string message, Category category, Priority priority)
{
MemoryAppender memoryAppender = new MemoryAppender();
log4net.Config.XmlConfigurator.Configure(new System.IO.FileInfo(#"C:\Users\Username\Documents\GitHub\MassSpecStudio\MassSpecStudio 2.0\source\MassSpecStudio\Core\app.config"));
bool log4netIsConfigured = log4net.LogManager.GetRepository().Configured;
switch(category)
{
case Category.Debug:
log.Debug(message);
break;
case Category.Warn:
log.Warn(message);
break;
case Category.Exception:
log.Error(message);
break;
case Category.Info:
log.Info(message);
break;
}
var events = memoryAppender.GetEvents(); // events is Null.
int esize = events.Length;
foreach (LoggingEvent loggingEvent in events)
{
LogItem logItem = new LogItem(loggingEvent.TimeStamp, loggingEvent.Level, loggingEvent.RenderedMessage);
LogItems.Add(logItem);
}
}
*UPDATE:
I have provided the following in the config file. How isn't my MemoryAppender hooking up into the logger properly?
<log4net>
<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
<file type="log4net.Util.PatternString" value="C:\temp\Logger_.txt" />
<param name="AppendToFile" value="true"/>
<param name="RollingStyle" value="Once"/>
<param name="RollingStyle" value="Date"/>
<datePattern value="yyyy-MM-dd_HHmmss" />
<lockingModle type="log4net.Appender.FileAppender+MinimalLock"/>
<preserveLogFileNameExtension value="true"/>
<maxSizeRollBackups value="30" />
<staticLogFileName value="false" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
<appender name="MemoryAppender" type="log4net.Appender.MemoryAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %message%newline" />
</layout>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="LogFileAppender" />
<appender-ref ref="MemoryAppender" />
</root>
Log4Net works on 'Loggers' and 'Appenders'. You need to connect an Appender to a Logger in order for it to receive the messages being logged. This can be done in code or in a config file. You appear to be doing a bit of both, by initialising log4net using the config file, then creating a MemoryAppender in code.
Problems:
You're initialising log4net every time this function is called. You only need to do this once per process.
You have created a new instance of MemoryAppender with every call to the function, when you probable only want one.
THE MAIN ISSUE: the MemoryAppender is not hooked up to the logger. If you definitely want to do this in code, see here: Programmatically adding and removing log appenders in log4net
Updated to answer your revised question:
To get the events from the single MemoryAppender in your .config file:
var appender = log4net.LogManager.GetRepository().GetAppenders().OfType<log4net.Appender.MemoryAppender>().Single(); // Assumes exactly one MemoryAppender
var events = appender.GetEvents();

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