Saturday 18 February 2017

configuring Log4Net For Web Applications

UPDATE: Mea Culpa! It seems like Log4Net has no problems with medium trust and an external log4net file. I have written an updated post that talks about the problem I did run into and how I solved it.
A while ago I wrote a quick and dirty guide to configuring Log4Net for ASP.NETUnfortunately, this technique does not work with ASP.NET 2.0 when running in medium trust.. This technique continues to work with medium trust!
While digging into the problem I found this blog post (from an aptly titled blog) by Kevin Jones.
This article from Microsoft discusses the ramifications of running ASP.NET 2.0 in medium trust more thoroughly. Here is a list of constraints placed on medium trust applications.
The main constraints placed on medium trust Web applications are:
  • OleDbPermission is not available. This means you cannot use the ADO.NET managed OLE DB data provider to access databases. However, you can use the managed SQL Server provider to access SQL Server databases.
  • EventLogPermission is not available. This means you cannot access the Windows event log.
  • ReflectionPermission is not available. This means you cannot use reflection.
  • RegistryPermission is not available. This means you cannot access the registry.
  • WebPermission is restricted. This means your application can only communicate with an address or range of addresses that you define in the <trust> element.
  • FileIOPermission is restricted. This means you can only access files in your application’s virtual directory hierarchy. Your application is granted Read, Write, Append, and PathDiscovery permissions for your application’s virtual directory hierarchy.
You are also prevented from calling unmanaged code or from using Enterprise Services.
Fortunately there is a way to specify that a configuration section within web.config should not require ConfigurationPermission. Simply add therequirePermission="false" attribute to the <section> declaration within the <configSections> area like so:
<configSections>
    <section name="log4net" 
      type="log4net.Config.Log4NetConfigurationSectionHandler
      , log4net"     
      requirePermission="false"/>
</configSections>
Unfortunately this applies to configuration sections within the web.config file. I have not found a way to specify that ASP.NET should not requireConfigurationPermission on an external configuration file. As I stated in my post on Log4Net, I prefer to put my Log4Net configuration settings in a separate configuration file. If anyone knows a way to do this, please let me know!
So in order to get Log4Net to work, I added the declaration above to the web.config file and copied the settings within the Log4Net.config file (pretty much cut and paste everything except the top xml declaration) into the web.config file. I then removed the assembly level XmlConfiguratorattribute from AssemblyInfo.cs as it is no longer needed. Instead, I added the following line to the Application_Start method in Global.asax.cs.
protected void Application_Start(Object sender, EventArgs e)
{
    log4net.Config.XmlConfigurator.Configure();
}
So in summary, here are the changes I made to get Log4Net to work again in medium trust.
  • Added the log4Net section declaration in the configSections section of web.config and made sure the requirePermission attribute is set to the value false.
  • Moved the log4Net settings into web.config.
  • Removed the assembly attribute XmlConfigurator
  • Added the call to XmlConfigurator.Configure() to theApplication_Start method in Global.asax.cs.
I have been working on getting the version of Subtext in our Subversion trunk to run in a medium trust environment, but there have been many challenges. Some of the components we use do not appear to run in a medium trust environment such as the FreeTextBox. Fortunately, we have a workaround for that issue which is to change the RichTextEditor node in web.config to use the PlainTextRichTextEditorProvider (which is a mouthful and should probably be renamed to PlainTextEditorProvider).

Log4net is not working on production machine, How to fix that?

Log4net is commonly used tool to log custom exceptions, same is in my current project. It is useful to write trace information or exception. By the way for un handled exceptions i am using Elmah which is doing pretty well.

Problem

We have smart deployment system to our test and development servers, but currently issue was that locally log4net works pretty cool but on production it does not. To configure I am using assembly attribute 
[assembly: log4net.Config.XmlConfigurator(Watch=true)]

Solving

Firstly i thought issue is with permission because file was not created, i added iis_iusrs and finally everyone with full permissions but it does not help.
Finally i started reading log4net faq and found interesting topic about release configuration which says 
For a command line application "as early as possible" probably is the class holding the Main method, for a Web-Application it would be your Global.asax class and for a Windows Service it would be the class deriving from ServiceBase.
Going further i found other topic which says
Using attributes can be a clearer method for defining where the application's configuration will be loaded from. However it is worth noting that attributes are purely passive. They are information only. Therefore if you use configuration attributes you must invoke log4net to allow it to read the attributes. A simple call toLogManager.GetLogger will cause the attributes on the calling assembly to be read and processed. Therefore it is imperative to make a logging call as early as possible during the application start-up, and certainly before any external assemblies have been loaded and invoked.
So i added code to global.asax

  protected void Application_Start()
        {
           var logger = LogManager.GetLogger("Default");        }
And finally everything works on all my servers. I can log my trace info, which helps me to solve issues if any.

log4net not working on production server

This is the log4net configuration in the web.config of the website.


<configuration>
      <log4net>
        <root>
          <level value="DEBUG" />
          <appender-ref ref="LogFileAppender" />
        </root>
        <appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
          <param name="File" value="log.txt" />
          <param name="AppendToFile" value="true" />
          <rollingStyle value="Size" />
          <maxSizeRollBackups value="10" />
          <maximumFileSize value="30MB" />
          <staticLogFileName value="false" />
          <layout type="log4net.Layout.PatternLayout">
            <param name="ConversionPattern" value="%-5p%d{yyyy-MM-dd hh:mm:ss} – %m%n" />
          </layout>
        </appender>
      </log4net>
    </configuration>
I also have a class library and this is its App.config file


<?xml version="1.0" encoding="utf-8" ?>
<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.txt" />
      <param name="AppendToFile" value="true" />
      <rollingStyle value="Size" />
      <maxSizeRollBackups value="10" />
      <maximumFileSize value="30MB" />
      <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>
</configuration>

This is how I call the log function on every class:
private static readonly ILog log = LogManager.GetLogger(typeof(AppDomain));
...and this is how i call it :
log.Error("\n\t=>" + ex.GetBaseException().Message + "\n\r" + " @ " + Environment.StackTrace);