Log4Net issue while using RollingFileAppender - c#

I am using log4net to perform logging in my application. I have bound my project to TFS. I have created a wrapper around log4net as below:
public static class TestLogger
{
private static readonly ILog log = LogManager.GetLogger("TestLogger");
static TestLogger()
{
log4net.Config.XmlConfigurator.Configure();
}
public static void LogInfo(string information)
{
log.Info(information);
}
public static void LogError(string erroMessage, Exception ex)
{
log.Error(erroMessage, ex);
}
public static void LogWarnings(string warningText)
{
log.Warn(warningText);
}
}
When I tried to execute the program from VS2010 I found that log file is not being created. I create another project (not bound to TFS) and perform some logging, it succeeded and created the file in bin/debug of application.
Below is my log4net configuration file.
<log4net>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender, log4net">
<file value="Log.txt" />
<appendToFile value="false" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="3" />
<maximumFileSize value="1GB" />
<layout type="log4net.Layout.PatternLayout, log4net">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
<logger name="TestLogger">
<level value="ALL" />
<appender-ref ref="RollingFileAppender" />
</logger>
</log4net>
Can anybody help in this issue?

Some troubleshooting tips:
define an absolute path to the Log file in your config file.
check the current working directory in your code (Environment.CurrentDirectory). If you're running under the VS debugger, and you haven't specified a working directory in the Debug tab of your project properties, it may well default to the current Visual Studio working directory.
I don't think being bound to TFS is relevant.

Just change this part
<appendToFile value="true" />

Maybe your application already uses some declarative configuration, which is somewhere burried in the code. Search for something like this:
[assembly: log4net.Config.XmlConfigurator(Watch=true)]
Otherwise try to get hold of the log4net repository with
log4net.LogManager.GetRepository(). It returns an object of the type ILoggerRepository. You can try to use this object to write some information about the current log4net configuration into the Console or somewhere else.

Try to turn on internal debugging as explained here. This should tell you what the problem is. If there is no output from internal debugging then you probably did not configure log4net.

Related

How to initialize log4net before the log file is created?

I would like to set the full path and the file name for the log file (I use log4net) and I would like to use the c:\ProgramData\Logs folder. I get the path of the ProgramData folder using the environment variable #PROGRAMDATA#.
I would like to set the path for the log file in the next way: I use a property in the App.config, and I set the value for this property in the class where I do the loggings.
My App.config file:
<configuration>
...
<log4net>
<appender name="Console" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<!-- Pattern to output the caller's file name and line number -->
<conversionPattern value="%5level [%thread] (%file:%line) - %message%newline" />
</layout>
</appender>
<appender name="AppRollingFile" type="log4net.Appender.RollingFileAppender">
<file type="log4net.Util.PatternString" value="%property{ProgramDataPath}\Logs\Application.log" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<appendToFile value="true" />
<maximumFileSize value="1000KB" />
<maxSizeRollBackups value="5" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="[%-5level][%d{yy-MM-dd HH:mm:ss,fff}] %m%n" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="Console" />
<appender-ref ref="AppRollingFile" />
</root>
</log4net>
</configuration>
And the code where I set the property:
static void Main(string[] args)
{
log4net.GlobalContext.Properties["ProgramDataPath"] = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
log4net.Config.XmlConfigurator.Configure();
My problem is that an empty log file is created before the value of the property is set (then the property it is null). The initialization of the log4net it is done before entering in the main function of the class where I set the property, so it will always be created an empty file in the application's folder: bin\Debug(null)\Logs\Application.log. After I set the property, everything works fine, because another Apllication.log file will be created in c:\ProgramData\Logs folder.
My question is that how can I set the value of the property before the empty log file is created/before entering in the main function of the class where I set the property, or what other solution is there?
Using the environment variable in the App.config as it is shown below did not work.
<file type="log4net.Util.PatternString" value="${PROGRAMDATA}\Logs\Application.log"/>
Try
<file type="log4net.Util.PatternString" value="${ProgramData}\Logs\Application.log"/>
The environment variables are case sensitive, which is why ${PROGRAMDATA} does not work.
Removing the assembly attribute should fix the problem:
[assembly: log4net.Config.XmlConfigurator(Watch=true)]
If you want log4net to watch app.config for configuration changes, use this code (I prefer to put log4net configuration in a separate log4net.config file for easier reuse):
log4net.GlobalContext.Properties["ProgramDataPath"] = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
FileInfo configFile = new FileInfo(Process.GetCurrentProcess().MainModule.FileName + ".config");
log4net.Config.XmlConfigurator.ConfigureAndWatch(configFile);

Log4Net Not Logging When Deployed

Using version 1.2.11. Logging works on my dev machine, but won't create the directory or log when deployed.
I tried:
giving full directory access to IUSR, Everyone, local users.
running the app pool as a local admin account.
to use internal debugging as Phil Haack describes here.
Stopped and started the app pool after each change.
Nothing is produced in the output file.
My log4Net config is below. Any thoughts on what to try next?
<?xml version="1.0"?>
<log4net debug="true">
<appender name="file" type="log4net.Appender.RollingFileAppender">
<file value="..\Logging\log.txt" />
<appendToFile value="true" />
<rollingStyle value="Composite" />
<datePattern value="yyyyMMdd" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="1MB" />
<threshold value="DEBUG" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
</appender>
<appender name="console" type="log4net.Appender.DebugAppender">
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d [%t] %-5p %c [%x] <%X{auth}> - %m%n" />
</layout>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="file" />
<appender-ref ref="console" />
</root>
</log4net>
If the directory and the file is not being created, then most likely, the configuration is not being read (and therefore used) at runtime.
I always forget to add the single line of code for Log4net that hooks up the configuration. This code usually appears in the bootstrap class in the application (e.g. Global.asax for an ASP.NET app).
XmlConfigurator.Configure(new System.IO.FileInfo(configFile)); // configFile being the path to the file.
Instead of the above in-line, you can add this attribute to the AssemblyInfo.cs file:
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
Either way, this will wire up log4net. More information is found in the Manual Configuration section of the log4net docs.
If you're using IIS, make sure the correct group has modify access to the Logs folder (usually IIS_USERS).
Sounds like a permissions issue to me. I almost always use a directory where I don't have to enable any special permissions for the applications to write the log files to.
Here is what I generally use with log4net:
<file type="log4net.Util.PatternString" value="${ALLUSERSPROFILE}/<Company Name>/Logs/<Program Name>/<Log file name>.txt" />
Of cource you'll need to substitute Company Name, Program Name and Log file name in the above with actual values.
This will write to the ProgramData folder where access is typically not restricted. You can navigate to this folder in File Explorer by typing %ProgramData% or %AllUsersProfile%
Another thing I like about this method is that it works on nearly every microsoft O/S. XP, Vista, 7, 8
You probably do not know where you are logging:
<file value="..\Logging\log.txt" />
Will is derived from your running directory, which is iis its directory. You can better use a full path like:
<file value="c:\Logging\log.txt" />
Then you can give the right access rights to the logging directory. Log4net will not create any directories as far as I know. So you have to create the c:\logging directory first.
Non of the answers worked for me until I put these lines to the web.config app settings:
<add key="log4net.Config" value="Log.config" />
<add key="log4net.Config.Watch" value="True" />

Issue using .net 2.0 Logger Class

I have been trying to use the class located here . But I have not been able to get this to work. I obviously do not understand something correctly, But I am curious how to get that example Logger class to work.
My research has sent me towards using MSBuild but the use of MSBuild correctly is still baffeling me. Any pointers would be helpful. I have built the logger class into a .dll,and referenced it in the project as well, but that is where my research seemed to run dry with helpful information.
My goal currently is just to get the above noted logger class working so I can use my own logger class.
That class is specifically for logging MSBuild events. If you want a generic logger that has nothing to do with MSBuild look at some of these alternatives:
MS Enterprise Library - Logging Application Block
Log4Net
Elmah (designed for logging ASP.NET errors, but can be used to log other events)
NLog
Don't be afraid of using a library to do the work. In the tutorial here for log4net it's a simple seven step process to start using a fully functional and scalable logging library. I'm going to inline pieces of the tutorial just in case the link ever dies.
First you build a very simple configuration section in your App.config file:
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,Log4net"/>
</configSections>
<log4net>
<root>
<level value="DEBUG" />
<appender-ref ref="LogFileAppender" />
</root>
<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender" >
<param name="File" value="log-file.txt" />
<param name="AppendToFile" value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="10MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
</appender>
</log4net>
</configuration>
For your needs you pretty much just need to change the value of the first param named File as it's already setup to append to a text file.
Next you'll need to run the configuration in some startup method, like Application_Start or the main method of your program.
log4net.Config.XmlConfigurator.Configure();
Finally, just use it by plugging in a couple of lines:
private static readonly ILog log = LogManager.GetLogger(typeof(Bar));
... (rest of class)
... (somewhere in a method) ... log.Debug("this is the first log message");

log multiple assemblies using log4net

After lots of issues, finally I managed to configure log4net for my window service.
I am pretty new to it and today I started configuring it. I have these below doubts.
1) I need to use that into multiple assemblies. Say I have an assembly 'A' which is added as reference in assembly 'B' which is mine main assembly where I have reference of log4net.I need to log both assembly 'A' and 'B'.
2) My application is multi-threaded and use lots of thread. So is log4net is thread safe?
3) I am using this below config in my app.config. I am not much aware what’s the use of it. But I don’t want to use unnecessary parameters.
<log4net>
<root>
<level value="DEBUG"/>
<appender-ref ref="LogFileAppender"/>
</root>
<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value="C:\logs\log.txt"/>
<param name="AppendToFile" value="true"/>
<rollingStyle value="Size"/>
<maxSizeRollBackups value="10"/>
<maximumFileSize value="100KB"/>
<staticLogFileName value="true"/>
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%-5p%d{yyyy-MM-dd hh:mm:ss} – %m%n"/>
</layout>
</appender>
</log4net>
Use <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> under appender section. I twill increase the logging performance.
log4net is threadsafe.
<maximumFileSize value="10MB" /> //For 100 Kb configuration there will be lot of files.
<datePattern value="_yyyyMMdd" /> //It will hint the logger to create a new file per date.
Create a static class for Logger and call the static function from every assembly where you want to use.
Sample Class for logging:
public static class Logger
{
static Logger()
{
XmlConfigurator.Configure();
}
public static void Log()
{
string methodName = new System.Diagnostics.StackFrame(1, true).GetMethod().Name;
string moduleName = new System.Diagnostics.StackFrame(1, true).GetMethod().ReflectedType.FullName;
var appLog = LogManager.GetLogger(loggername);
appLog.Error(...);
}
}
that's not a problem; just use ILog as usual in assembly B.
just make sure you call Configure() once in your application's lifetime.
Yes.
I recommend familiarizing yourself with log4net. a simple google search or a look at the docs should do the trick.
<root>
<level value="DEBUG"/>
<appender-ref ref="LogFileAppender"/>
</root>
It will log only in debug mode, so make following entry in config:
<root>
<level value="ALL"/>
<appender-ref ref="LogFileAppender"/>
</root>

log4net not working in dll

I'm currently having issues with getting log4net to work within a particular dll. I'm currently using log4net in other dlls being called by my test app and logging is working fine within those dlls and also within my test app. It's this one particular dll that I'm having trouble with. Here is snippet of code from the dll I'm having trouble with.
//This is from ABC.dll
public class SessionFactory
{
protected static ISessionFactory sessionFactory;
private static readonly ILog log = LogManager.GetLogger(typeof(SessionFactory));
private static void Init()
{
try
{
//Read the configuration from hibernate.xml.cfg or app.config
Configuration normalConfig = new Configuration().Configure();
ConfigureNhibernateValidator(normalConfig);
log.Debug("Initializing session factory");
sessionFactory = Fluently.Configure(normalConfig)
.Mappings(m =>
m.FluentMappings
.AddFromAssemblyOf<OrderHeaderMap>()
.Conventions.AddFromAssemblyOf<PascalCaseColumnNameConvention>())
.ProxyFactoryFactory("NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu")
.BuildSessionFactory();
log.Debug("Finished initializing the session factory");
}
catch(Exception ex)
{
//Code not shown
}
}
}
In my test app I am calling:
log4net.Config.XmlConfigurator.Configure();
Here is my log4net configuration in my App.config file:
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>
<log4net>
<!-- ALL|DEBUG|INFO|WARN|ERROR|FATAL|OFF -->
<root>
<level value="DEBUG"/>
<appender-ref ref="SpeedTest"/>
</root>
<!-- This is a default logger that nhibernate uses to push out all the SQL statements to-->
<logger name="NHibernate.SQL" additivity="false">
<level value="DEBUG"/>
<appender-ref ref="NHibernateConsoleLog"/>
<appender-ref ref="NHibernateFileLog"/>
</logger>
<!-- This is a default logger that nhibernate uses to push out all the debugging type information to-->
<logger name="NHibernate" additivity="false">
<level value="DEBUG"/>
<appender-ref ref="NHibernateFileLog"/>
</logger>
<appender name="NHibernateConsoleLog" type="log4net.Appender.TraceAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline"/>
</layout>
</appender>
<appender name="NHibernateFileLog" type="log4net.Appender.RollingFileAppender">
<file value="Logs/nhibernate.txt" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="10MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d{HH:mm:ss.fff} [%t] %-5p %c - %m%n" />
</layout>
</appender>
<appender name="SpeedTest" type="log4net.Appender.RollingFileAppender">
<file value="Logs/SpeedTest.txt" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="10MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d{HH:mm:ss.fff} [%t] %-5p %c - %m%n" />
</layout>
</appender>
</log4net>
</configuration>
Again logging is working fine within my test application using the SpeedTest appender but the logging within the above snippet of code is not working. I set breakpoints above on when it initializes the logger and it seems to hit it. I can post the log4net debug output if necessary but I didn't really see much. Just let me know if you need it and I will post.
Any suggestions as to why logging is not being recorded in the above snippet of code?
It seems that this issue was stemming from me changing the directory to all my external dependencies (log4net being one of them) awhile back in TFS. All I did was drop all my references in my visual studio project and re-add them from my new dependencies folder and everything worked as expected after this. Thanks for all those that helped here.
My suspicion would be that it isn't reading the configuration from the configuration file when you call configure.
If you add the following lines to your application, what do you see (either on the console, or in IDE output window, or by stepping through in the debugger):
var log4netConfig = ConfigurationManager.GetSection("log4net");
var log4netConfigIsNull = log4netConfig == null;
Console.WriteLine(log4netConfigIsNull);
Does it look like the configuration is actually available from the configuration file?
[Edit: in response to your comment]
If you now add another line of debug code to your app:
Console.WriteLine(log.IsDebugEnabled);
what output do you get? Does the logger think it is configured for debug logging? (I'm particularly interested in the behaviour of this in, or after, SessionFactory.Init).
The immediate thought would be that your logging code isn't getting hit, possibly due to an exception being thrown prior to your first log4net call. Can you put a log entry into a finally block, just to test that the logger works?

Categories

Resources