Setting up Log4Net to log output from a Class Library - c#

I'm trying to setup Log4Net (this is my first time using Log4Net) to log to a text file in an assembly. I'm not getting any errors, but it's also not working. I can breakpoint the lines where I am logging my output and see that they are reached, but like I say nothing happens.
Where am I going wrong?
I have added the following to my packages.config file, inside the <packages> attribute:
<log4net>
<appender name="FileAppender" type="log4net.Appender.FileAppender,log4net">
<file value="c:\CTI\log.txt" />
<appendToFile value="true" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %level %logger - %message%newline" />
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="INFO" />
<levelMax value="FATAL" />
</filter>
</appender>
<root>
<level value="DEBUG"/>
<appender-ref ref="FileAppender"/>
</root>
</log4net>
</configuration>
I have added the following line to AssemblyInfo.cs:
[assembly: log4net.Config.XmlConfigurator(Watch=true)]
I added the Log4Net assembly using NuGet and I am logging like this:
private log4net.ILog _Log;
_Log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
_Log.Debug("FooBar");
Like I say, no errors but nothing happens either.
What am I missing?

One thing that is wrong is that you are adding the log4net configuration section to the nuget config file (packages.config).
You can have the configuration in the app/web config or in a separate file to which you point from the appSettings, e.g.
configuration is in a file called config.log4net (the copy to output directory attribute of the file is set to copy always) and you add the following entry in app/web.config:
<add key="log4net.config" value="config.log4net"/>
If you don't want to depend on a web/app configuration, you can set the ConfigFileExtension property of the XmlConfiguratorAttribute attribute in AssemblyInfo.cs:
[assembly: log4net.Config.XmlConfigurator(ConfigFileExtension = "log4net", Watch = true)]
Then name the log4net configuration file the same as your exe/assembly plus the configured extension, e.g. MyApplication.exe.log4net or MyLibrary.dll.log4net
Another thing that is wrong is your appender filter. The range that you have set excludes DEBUG level, which you expect to log. Here are all logging levels:
ALL
DEBUG
INFO
WARN
ERROR
FATAL
OFF
As you can see, DEBUG is not between INFO and FATAL.

Related

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/

why log4net config file is not being read

I have a file log4net.xml in the root of my solution. The file property for copying to bin is set to Always copy. I have confirmed that the file copies to the bin directory.
Within the config I have set up a file appender (basically a copy paste from the documentation):
<appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
<file value="Logs\\log.log" />
<appendToFile value="true" />
<rollingStyle value="Date"/>
<datePattern value="yyyyMMdd-HHmmss" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
</appender>
I also have this line in AssemblyInfo.cs
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.xml", Watch = true)]
And loggers are set up like this in code files:
private static ILog LOGGER = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
I added log4net.Config.XmlConfigurator.Configure(); (and also with FileInfo parameter) to the main Program.cs too.
However if I execute the program the expected log file is not created. I suspect log4net isn't even reading the config file.
Am I missing something? Executing from within VS also doesn't work (though somehow it is picking up the Console Appender part).
Similar posts:
StackOverflow question 1 -- not applicable
StackOverflow question 2 -- not applicable
StackOverflow question 3 -- conforms already
Thanks in advance.
EDIT
So I got this working in VS by deleting a copy/pasted part from the documentation:
<root>
<level value="DEBUG" />
<appender-ref ref="A1" />
</root>
However, running from the exe still doesn't work
Easiest way is to debug log4net error is to dump them to a file under C:\tmp\log4net.txt. This won't answer your original question, but it will give you a clue where to look for.
How do I enable log4net internal debugging?
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="log4net.Internal.Debug" value="true"/>
</appSettings>
</configuration>
<configuration>
...
<system.diagnostics>
<trace autoflush="true">
<listeners>
<add
name="textWriterTraceListener"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="C:\tmp\log4net.txt" />
</listeners>
</trace>
</system.diagnostics>
...
</configuration>
I think the issue might be with the double \\ in your path in the config file. Given that when you run the program in Visual Studio and the Console Appender part works, that would seem to indicate that the config file is being read, it just can't write to the file because the path isn't valid. I'm not that familiar with Log4Net, so I don't know if an invalid path would throw an exception or not - it might be getting swallowed.
Try changing the file value in your config to one backslash, like this:
<file value="Logs\log.log" />
I worked this out, I don't know if it's the proper fix - and I have no idea why it worked once in VS - but I think it's just that the config file is not configured properly.
Firstly, since there is a declaration of the file in AssemblyInfo.cs there is no need for log4net.Config.XmlConfigurator.Configure();.
Secondly, I simply had to add both appenders to the root tag:
<root>
<level value="DEBUG" />
<appender-ref ref="A1" />
<appender-ref ref="RollingFile" />
</root>
And that's it. VS outputs on console as well as file, and exe outputs to file.
For the Console application. we can use to configure using the following code
// Path of your log4net config file
string configFilePath = #"/log4net.config";
XmlDocument log4netConfig = new XmlDocument();
log4netConfig.Load(File.OpenRead(configFilePath));
var repo = LogManager.CreateRepository(
Assembly.GetEntryAssembly(), typeof(log4net.Repository.Hierarchy.Hierarchy));
log4net.Config.XmlConfigurator.Configure(repo, log4netConfig["log4net"]);

log4net EventLog custom logname created, but not used

In a project, i'm using log4net to write down in the event log. I need to create a custom log so all will go there. I have tried to add the event to different logs, and it worked, but for some reasons, now it is impossible to change the logname from the config file. Even if I change it, it will keep the previous one and log into it. Here is a sample of my app.config:
<appender name="EventLogAppender" type="log4net.Appender.EventLogAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date{yyyy-MMMM-dd HH:mm:ss, fff} [%thread] %level %message %exception%newline"/>
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="DEBUG" />
<levelMax value="FATAL" />
</filter>
<ApplicationName>TestLoggerFichierConfig</ApplicationName>
<LogName>AgentLogger</LogName>
</appender>
I read that the event log must be restarted when adding a new log so the recent events will be displayed in it. I did this, and it allowed me to see the new log that has been created, but nothing will go there. Is it possible to force Log4Net to stop using the previous log to rather use the one I defined in the app.config?
Thanks for the help.
Update:
It seems that le EventLogs recognizes the source application and decide in wich log to put the new events since he remembers where it previously went. When I first set the logName, it works fine. If I stop the app, change the logname and restart it, the event will still go to the previous log. If the logName does not exists in the event log, it will be created, but not used! There might be something to do, but it is not in the side of log4net, and it may be dangerous to change the windows settings at this level. I created two eventLogAppender on the same app.config file, both pointing at different logs. the events got to the same log though. It is being obvious that the problem doesn't come from log4net, and the solution to my problem will not be solved by code. Thanks for the great advices though.
Something is probably wrong with your configuration and it is simply not telling you about it because log4net itself is designed to never, ever throw errors.
You can turn on internal debugging for log4net, but don't deploy to production with log4net debugging turned on. Weirdness will eventually happen if deploy your product with the log4net debugging switch on.
http://haacked.com/archive/2006/09/27/Log4Net_Troubleshooting.aspx
http://logging.apache.org/log4net/release/faq.html (see the troubleshooting section)
I ran into this and it wasn't down to log4net but the re-mapping of the source to a new custom log. I took log4net out of the equation and finding that the problem occurred usint the EventLog class directly, I eventually found EventLog.CreateEventSource is not creating a custom log
I think it's also the reason behind this Windows service always writes to custom log and application log
First and foremost, I'd encourage you to turn on internal debugging, as found in the link ntcolonel posted. Add this to your config file:
<add key="log4net.Internal.Debug" value="true"/>
Perhaps I am not understanding your question entirely, but I'd like to ensure you have both created the appender and properly tell log4net that you want to actually use that appender:
<log4net debug="true">
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="Logs\SomeApplication.xml"/>
<appendToFile value="true"/>
<rollingStyle value="Size"/>
<countDirection value="1"/>
<maxSizeRollBackups value="30"/>
<maximumFileSize value="10MB"/>
<staticLogFileName value="true"/>
<lockingModel type="log4net.Appender.FileAppender+MinimalLock"/>
<layout type="log4net.Layout.XmlLayoutSchemaLog4j">
<locationInfo value="true"/>
</layout>
</appender>
<appender name="SmtpAppender" type="log4net.Appender.SmtpAppender">
<to value="SomeDistributionList#somehost.com"/>
<from value="SomeApplication#somehost.com"/>
<subject type="log4net.Util.PatternString" value="Some Application Error - %property{log4net:HostName}"/>
<smtpHost value="smtp.somehost.com"/>
<bufferSize value="1"/>
<threshold value="ERROR"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %property{log4net:HostName} %logger %level %newline%newline%property{ExceptionThrottleInformation}%newline%newline%message%newline"/>
</layout>
<filter type="SomeNamespace.SomeSubNamespace.Log4Net.ExceptionThrottleFilter, SomeSubNamespace">
<threshold value="10"/>
<thresholdTimeoutSeconds value="60"/>
<timeoutSecondsBetweenMessages value="600000"/>
<exceptionText value="Timeout expired"/>
</filter>
</appender>
<appender name="DatabaseAppender" type="SomeNamespace.SomeSubNamespace.DatabaseTraceAppender, SomeSubNamespace">
<hoursToKeepInformationalTraces value="48"/>
<hoursToKeepErrorTraces value="96"/>
<threshold value="INFO"/>
</appender>
<root>
<level value="INFO"/>
<appender-ref ref="RollingFileAppender"/>
<appender-ref ref="SmtpAppender"/>
<appender-ref ref="DatabaseAppender"/>
</root>
Note that while I have multiple appenders, I reference which to call within the root tag. Since you didn't post your whole config file, it's tough to tell if everything is matching as it should.

log4net problem under my solution

Under my VS2010 solution I've this situation:
WEBSITE
Library1
Library2
On global.asax.cs I initialize the log4net configuration using:
private static log4net.ILog _logger = log4net.LogManager.GetLogger("globalASAX");
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
log4net.Config.XmlConfigurator.Configure();
_logger.Info("[APPLICATION START] " + DateTime.Now.ToString());
}
It works fine and Application start message is correclty available on log.txt file. The problem happens when I try to use log something on the classes available on DLL Library1 or Library2.
I added the row:
private static log4net.ILog _logger = log4net.LogManager.GetLogger(typeof(ImageRepository));
but when I try to all the _logger.error("blabla") nothing happens on log file; all properties of _logger are false (i.e. isdebugenable=false). How can I fix that? I followed the instruction available here:
http://logging.apache.org/log4net/release/manual/configuration.html
the configuration of log4net is under web.config file:
<log4net>
<appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
<file type="log4net.Util.PatternString">
<conversionPattern value="log\explorer-log-%date{ yyyy.MM.dd.HH.mm.ss}-[%processid].log"/>
</file>
<appendToFile value="true"/>
<maximumFileSize value="1024KB"/>
<maxSizeRollBackups value="5"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %level %logger - %message%newline"/>
</layout>
</appender>
<root>
<level value="DEBUG"/>
<appender-ref ref="RollingFile"/>
</root>
</log4net>
anyone can help me?
thanks,
Andrea
I suspect log4net cannot find the logger for your type ImageRepository. As a quick check create a named logger and try calling it.
private static log4net.ILog _logger = log4net.LogManager.GetLogger("FooLog");
And config
<root>
<level value="DEBUG"/>
<appender-ref ref="RollingFile"/>
</root>
<logger name="FooLog">
<level value="DEBUG"/>
<appender-ref ref="RollingFile"/>
</logger>
In theory this should work (as I'm sure you are aware). In general, however, there are two areas to check when you don't get anything logged to a file. The first area I would check would be the file appender itself. Text files can be locked, which can cause messages to be lost. The other thing I would check is to be sure that log4net is properly initialized in the library. It should be, but it doesn't hurt to check. If neither of these solutions help, try turning on the debugging of log4net itself to see what error messages are coming up. Here is a link that shows you how to turn on those messages:
http://haacked.com/archive/2006/09/27/Log4Net_Troubleshooting.aspx

How to include log4net for a class library?

I want to implement logging function into a class library, which is itself referenced in a webservice. I tried to add app.config and did everything needed, but it seems that when an exception is thrown, log4net simply does nothing.
my app.config
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>
<log4net>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="D:\\mylogfile.txt" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="5" />
<maximumFileSize value="10MB" />
<staticLogFileName value="true" />
<filter type="log4net.Filter.StringMatchFilter">
<stringToMatch value="test" />
</filter>
<filter type="log4net.Filter.StringMatchFilter">
<stringToMatch value="error" />
</filter>
<filter type="log4net.Filter.DenyAllFilter" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %level %logger - %message%newline%exception" />
</layout>
</appender>
<root>
<level value="INFO"/>
<appender-ref ref="RollingFileAppender"/>
<appender-ref ref="ConsoleAppender" />
</root>
</log4net>
in AssemblyInfo.cs:
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "app.config")]
in LogManager.cs:
private static readonly ILog Log = log4net.LogManager.GetLogger
(MethodBase.GetCurrentMethod().DeclaringType);
public static void WriteLog(Exception ex)
{
Log.Error(ex);
}
Can you please tell me what's wrong? How can I get log4net working for my class library?
Thank you
At runtime, config file is always used from host application, unless declared explicitly. Here in case, web.config is being used not app.cofig. Rather mention some other custom config file name and ensure that file is copied in virtual directory of web service. Also as chibacity said, ensure permission on log file. Better keep it in app_data folder for web service host.
You could use some kind of injection, either you build a simple one like:
public interface ILogger
{
void LogInfo(string message);
.
.
.
}
And then you just inject something that matches that interface, like a wrapper for log4net or such.
But, I think the most correct thing is to not log in the class library. Why I think so is because the library itself is not the application, your web service is so your web service should decide what to log. If you want to log exceptions just don't catch them in the class library and let your web service handle the logging. This will also make it easier to centralize the logging.
Please see my answer to the following question:
Use log4net in SDK
It has a log configuration routine that will construct a complete path to a log4net config file. As you are in a webservice it my not be looking where you expect for "app.config".
Also make sure that you have permission to write to "D:\mylogfile.txt" from your webservice.

Categories